home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Unix / Shells / zsh / Source / src / zle_tricky.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-04-07  |  59.7 KB  |  2,957 lines

  1. /*
  2.  *
  3.  * zle_tricky.c - expansion and completion
  4.  *
  5.  * This file is part of zsh, the Z shell.
  6.  *
  7.  * This software is Copyright 1992 by Paul Falstad
  8.  *
  9.  * Permission is hereby granted to copy, reproduce, redistribute or otherwise
  10.  * use this software as long as: there is no monetary profit gained
  11.  * specifically from the use or reproduction of this software, it is not
  12.  * sold, rented, traded or otherwise marketed, and this copyright notice is
  13.  * included prominently in any copy made.
  14.  *
  15.  * The author make no claims as to the fitness or correctness of this software
  16.  * for any use whatsoever, and it is provided as is. Any use of this software
  17.  * is at the user's own risk.
  18.  *
  19.  */
  20.  
  21. #define ZLE
  22. #include "zsh.h"
  23. #include    <pwd.h>
  24.  
  25. #ifdef HAS_NIS
  26. #include    <rpc/types.h>
  27. #include    <rpc/rpc.h>
  28. #include    <rpcsvc/ypclnt.h>
  29. #include    <rpcsvc/yp_prot.h>
  30.  
  31. #define PASSWD_FILE    "/etc/passwd"
  32. #define PASSWD_MAP    "passwd.byname"
  33.  
  34. typedef struct {
  35.     int len;
  36.     char *s;
  37. } dopestring;
  38.  
  39. #endif
  40.  
  41. #define inststr(X) inststrlen((X),1,-1)
  42.  
  43. extern char *glob_pre, *glob_suf;
  44.  
  45. /*
  46.  * We store the following prefizes/suffizes:
  47.  * lpre/lsuf -- what's on the line
  48.  * rpre/rsuf -- same as lpre/lsuf, but expanded
  49.  *   ... and if we are completing files, too:
  50.  * ppre/psuf -- the path prefix/suffix
  51.  * fpre/fsuf -- prefix/suffix of the pathname component the cursor is in
  52.  * prpre     -- ppre in expanded form usable for opendir
  53.  */
  54.  
  55. static int we, wb, usemenu, useglob;
  56.  
  57. static char **menuarr, **menucur;
  58. static int menupos, menulen, menuend, menuwe;
  59. static Lklist matches;
  60. static char **amatches;
  61. static int nmatches;
  62. static int ispattern;
  63. static Comp patcomp, filecomp;
  64. static char *lpre, *lsuf;
  65. static char *rpre, *rsuf;
  66. static char *ppre, *psuf, *prpre;
  67. static char *fpre, *fsuf;
  68. static char *mpre, *msuf;
  69. static char ic;
  70. static int lpl, lsl, rpl, rsl, fpl, fsl, noreal;
  71. static int ab, ae;
  72. static int addwhat;
  73. static char *firstm, *shortest, *qword;
  74. static int shortl, amenu;
  75.  
  76. int usetab()
  77. {                /**/
  78.     unsigned char *s = line + cs - 1;
  79.  
  80.     for (; s >= line && *s != '\n'; s--)
  81.     if (*s != '\t' && *s != ' ')
  82.         return 0;
  83.     return 1;
  84. }
  85.  
  86. #define COMP_COMPLETE 0
  87. #define COMP_LIST_COMPLETE 1
  88. #define COMP_SPELL 2
  89. #define COMP_EXPAND 3
  90. #define COMP_EXPAND_COMPLETE 4
  91. #define COMP_LIST_EXPAND 5
  92. #define COMP_ISEXPAND(X) ((X) >= COMP_EXPAND)
  93.  
  94. void completeword()
  95. {                /**/
  96.     usemenu = isset(MENUCOMPLETE);
  97.     useglob = isset(GLOBCOMPLETE);
  98.     if (c == '\t' && usetab())
  99.     selfinsert();
  100.     else
  101.     docomplete(COMP_COMPLETE);
  102. }
  103.  
  104. void menucompleteword()
  105. {                /**/
  106.     usemenu = 1;
  107.     useglob = isset(GLOBCOMPLETE);
  108.     if (c == '\t' && usetab())
  109.     selfinsert();
  110.     else
  111.     docomplete(COMP_COMPLETE);
  112. }
  113.  
  114. void listchoices()
  115. {                /**/
  116.     usemenu = isset(MENUCOMPLETE);
  117.     useglob = isset(GLOBCOMPLETE);
  118.     docomplete(COMP_LIST_COMPLETE);
  119. }
  120.  
  121. void spellword()
  122. {                /**/
  123.     usemenu = useglob = 0;
  124.     docomplete(COMP_SPELL);
  125. }
  126.  
  127. void deletecharorlist()
  128. {                /**/
  129.     char **mc =   menucur;
  130.  
  131.     usemenu = isset(MENUCOMPLETE);
  132.     useglob = isset(GLOBCOMPLETE);
  133.     if (cs != ll)
  134.     deletechar();
  135.     else
  136.     docomplete(COMP_LIST_COMPLETE);
  137.  
  138.     menucur = mc;
  139. }
  140.  
  141. void expandword()
  142. {                /**/
  143.     usemenu = useglob = 0;
  144.     if (c == '\t' && usetab())
  145.     selfinsert();
  146.     else
  147.     docomplete(COMP_EXPAND);
  148. }
  149.  
  150. void expandorcomplete()
  151. {                /**/
  152.     usemenu = isset(MENUCOMPLETE);
  153.     useglob = isset(GLOBCOMPLETE);
  154.     if (c == '\t' && usetab())
  155.     selfinsert();
  156.     else
  157.     docomplete(COMP_EXPAND_COMPLETE);
  158. }
  159.  
  160. void menuexpandorcomplete()
  161. {                /**/
  162.     usemenu = 1;
  163.     useglob = isset(GLOBCOMPLETE);
  164.     if (c == '\t' && usetab())
  165.     selfinsert();
  166.     else
  167.     docomplete(COMP_EXPAND_COMPLETE);
  168. }
  169.  
  170. void listexpand()
  171. {                /**/
  172.     usemenu = isset(MENUCOMPLETE);
  173.     useglob = isset(GLOBCOMPLETE);
  174.     docomplete(COMP_LIST_EXPAND);
  175. }
  176.  
  177. void reversemenucomplete()
  178. {                /**/
  179.     if (!menucmp) {
  180.     menucompleteword();    /* better than just feep'ing, pem */
  181.     return;
  182.     }
  183.     if (menucur == menuarr)
  184.     menucur = menuarr + arrlen(menuarr) - 1;
  185.     else
  186.     menucur--;
  187.     do_single(*menucur);
  188. }
  189.  
  190. /*
  191.  * Accepts the current completion and starts a new arg,
  192.  * with the next completions. This gives you a way to accept
  193.  * several selections from the list of matches.
  194.  */
  195. void acceptandmenucomplete()
  196. {                /**/
  197.     if (!menucmp) {
  198.     feep();
  199.     return;
  200.     }
  201.     cs = menuend;
  202.     inststrlen(" ", 1, 1);
  203.     if (mpre)
  204.     inststrlen(mpre, 1, -1);
  205.     if (msuf)
  206.     inststrlen(msuf, 0, -1);
  207.     menupos = cs;
  208.     menuend = cs + (msuf ? strlen(msuf) : 0);
  209.     menulen = 0;
  210.     menuwe = 1;
  211.     menucompleteword();
  212. }
  213.  
  214. static int lincmd, linredir, lastambig, inwhat, haswhat;
  215. static char *cmdstr;
  216.  
  217. #define IN_NOTHING 0
  218. #define IN_CMD     1
  219. #define IN_MATH    2
  220. #define IN_COND    3
  221. #define IN_ENV     4
  222.  
  223. #define HAS_SUFFIX  1
  224. #define HAS_FILES   2
  225. #define HAS_MISC    4
  226. #define HAS_PATHPAT 8
  227.  
  228. int checkparams(p)    /**/
  229. char *p;
  230. {
  231.     int t0, n, l = strlen(p), e = 0;
  232.     struct hashnode *hn;
  233.  
  234.     for (t0 = paramtab->hsize - 1, n = 0; n < 2 && t0 >= 0; t0--)
  235.     for (hn = paramtab->nodes[t0]; n < 2 && hn; hn = hn->next)
  236.         if (pfxlen(p, hn->nam) == l) {
  237.         n++;
  238.         if (strlen(hn->nam) == l)
  239.             e = 1;
  240.         }
  241.  
  242.     return (n == 1) ? (getsparam(p) != NULL) : 
  243.     (!menucmp && e && isset(RECEXACT));
  244. }
  245.  
  246. int cmphaswilds(str)        /**/
  247. char *str;
  248. {
  249.     if ((*str == Inbrack || *str == Outbrack) && !str[1])
  250.     return 0;
  251.     if (str[0] == '%')
  252.     return 0;
  253.     for (; *str; str++) {
  254.     if (*str == String || *str == Qstring) {
  255.         if (*++str == Inbrace) {
  256.         for (str++; *str; str++)
  257.             if (*str == Outbrace)
  258.             break;
  259.         }
  260.         else
  261.         for (; *str; str++)
  262.             if (*str != '^' && *str != Hat &&
  263.             *str != '=' && *str != Equals &&
  264.             *str != '#' && *str != Pound &&
  265.             *str != '~' && *str != Tilde &&
  266.             *str != '+')
  267.             break;
  268.     }
  269.     if (*str == Pound || *str == Hat || *str == Star ||
  270.         *str == Bar || *str == Inbrack || *str == Inang ||
  271.         *str == Quest || (*str == Inpar && str[1] == ':'))
  272.         return 1;
  273.     }
  274.     return 0;
  275. }
  276.  
  277. void docomplete(lst)        /**/
  278. int lst;
  279. {
  280.     char *s;
  281.     int olst = lst, dh;
  282.  
  283.     if (menucmp) {
  284.     do_menucmp(lst);
  285.     return;
  286.     } else if ((amenu=(isset(AUTOMENU) &&
  287.                (lastcmd & ZLE_MENUCMP) &&
  288.                lastambig)))
  289.     usemenu = 1;
  290.  
  291.     dh = doexpandhist();
  292.     if (dh == 0 || dh == 1)
  293.     return;
  294.  
  295.     inwhat = IN_NOTHING;
  296.     qword = NULL;
  297.     s = get_comp_string();
  298.     freeheap();
  299.     if (inwhat == IN_ENV)
  300.     lincmd = 0;
  301.     if (s) {
  302.     if (lst == COMP_EXPAND_COMPLETE) {
  303.         char *q = s;
  304.  
  305.         if (*q == Equals) {
  306.         q = s + 1;
  307.         if (gethnode(q, cmdnamtab) || hashcmd(q, pathchecked))
  308.             if (isset(RECEXACT))
  309.             lst = COMP_EXPAND;
  310.             else {
  311.             int t0, n = 0;
  312.             char *fc;
  313.             struct hashnode *hn;
  314.  
  315.             for (t0 = cmdnamtab->hsize - 1; t0 >= 0; t0--)
  316.                 for (hn = cmdnamtab->nodes[t0]; hn; hn = hn->next) {
  317.                 if (strpfx(q, hn->nam) &&
  318.                     ISEXCMD(((Cmdnam) hn)->flags) &&
  319.                     (fc = findcmd(hn->nam))) {
  320.                     zsfree(fc);
  321.                     n++;
  322.                 }
  323.                 if (n == 2)
  324.                     break;
  325.                 }
  326.  
  327.             if (n == 1)
  328.                 lst = COMP_EXPAND;
  329.             }
  330.         } else if (*q != Tilde) {
  331.         for (; *q && *q != String; q++);
  332.         if (*q == String && q[1] != Inpar && q[1] != Inbrack) {
  333.             if (*++q == Inbrace) {
  334.             for (++q; *q && *q != Outbrace; q++);
  335.             if (*q && q - s + 1 == cs - wb)
  336.                 lst = COMP_EXPAND;
  337.             } else {
  338.             char *t, sav;
  339.  
  340.             for (; *q; q++)
  341.                 if (*q != '^' && *q != Hat &&
  342.                 *q != '=' && *q != Equals &&
  343.                 *q != '#' && *q != Pound &&
  344.                 *q != '~' && *q != Tilde &&
  345.                 *q != '+')
  346.             break;
  347.             for (t = q; *q && (ialnum(*q) || *q == '_'); q++);
  348.             sav = *q;
  349.             *q = '\0';
  350.             if (cs - wb == q - s && checkparams(t))
  351.                 lst = COMP_EXPAND;
  352.             *q = sav;
  353.             }
  354.             if (lst != COMP_EXPAND)
  355.             lst = COMP_COMPLETE;
  356.         }
  357.         q = s;
  358.         }
  359.         if (lst == COMP_EXPAND_COMPLETE) {
  360.         for (q = s; *q; q++)
  361.             if (*q == Tick || *q == Qtick ||
  362.             *q == String || *q == Qstring)
  363.             break;
  364.         lst = *q ? COMP_EXPAND : COMP_COMPLETE;
  365.         }
  366.         if (unset(GLOBCOMPLETE) && cmphaswilds(s))
  367.         lst = COMP_EXPAND;
  368.     }
  369.     if (lincmd && (inwhat == IN_NOTHING))
  370.         inwhat = IN_CMD;
  371.  
  372.     if (lst == COMP_SPELL) {
  373.         char **x = &s;
  374.         char *q = s;
  375.  
  376.         for (; *q; q++)
  377.         if (INULL(*q))
  378.             *q = Nularg;
  379.         untokenize(s);
  380.         cs = wb;
  381.         foredel(we - wb);
  382.     /* call the real spell checker, ash@aaii.oz.zu */
  383.         spckword(x, NULL, NULL, !lincmd, 0);
  384.         inststr(*x);
  385.     } else if (COMP_ISEXPAND(lst)) {
  386.         char *ol = (olst == COMP_EXPAND_COMPLETE) ?
  387.         dupstring((char *) line) : (char *) line;
  388.         int ocs = cs, ne = noerrs;
  389.  
  390.         noerrs = 1;
  391.  
  392.         doexpansion(s, lst, lincmd);
  393.         lastambig = 0;
  394.  
  395.         noerrs = ne;
  396.  
  397.         if (olst == COMP_EXPAND_COMPLETE &&
  398.         !strcmp(ol, (char *) line)) {
  399.  
  400.         cs = ocs;
  401.         errflag = 0;
  402.  
  403.         untokenize(s);
  404.         docompletion(s, lst, lincmd);
  405.         }
  406.     }
  407.     else
  408.         docompletion(s, lst, lincmd);
  409.     zsfree(s);
  410.     }
  411.     popheap();
  412.     lexrestore();
  413.     zsfree(qword);
  414. }
  415.  
  416. void do_menucmp(lst)        /**/
  417. int lst;
  418. {
  419.     if (lst == COMP_LIST_COMPLETE) {
  420.     amatches = menuarr;
  421.     listmatches();
  422.     return;
  423.     }
  424.     if (!*++menucur)
  425.     menucur = menuarr;
  426.     do_single(*menucur);
  427. }
  428.  
  429. int addedx;            /* 1 if x added to complete in a blank between words */
  430. int instring;            /* 1 if we are completing in a string */
  431.  
  432. void addx(ptmp)            /**/
  433. char **ptmp;
  434. {
  435.     if (!line[cs] || inblank(line[cs]) || line[cs] == ')') {
  436.     *ptmp = (char *)line;
  437.     line = (unsigned char *)ncalloc(strlen((char *)line) + 2);
  438.     memcpy(line, *ptmp, cs);
  439.     line[cs] = 'x';
  440.     strcpy((char *)line + cs + 1, (*ptmp) + cs);
  441.     addedx = 1;
  442.     } else {
  443.     addedx = 0;
  444.     *ptmp = NULL;
  445.     }
  446. }
  447.  
  448. char *get_comp_string()
  449. {                /**/
  450.     int t0, tt0, i, j, k, l, cp, rd, inc = 0, opb = -1, sl, im = 0, ocs;
  451.     char *s = NULL, *linptr, *tmp, *p, *tt = NULL, *q = NULL;
  452.  
  453.     noaliases = isset(COMPLETEALIASES);
  454.  
  455.     instring = 0;
  456.     for (i = j = k = l = 0, q = p = (char *)line; p < (char *)line + cs; p++)
  457.     if (*p == '`' && !(k & 1))
  458.         i++, q = p;
  459.     else if (*p == '\"' && !(k & 1))
  460.         j++;
  461.     else if (*p == '\'' && !(j & 1))
  462.         k++;
  463.     else if (*p == '(' && p[1] == '(')
  464.         l++, p++;
  465.     else if (*p == ')' && p[1] == ')')
  466.         l--, p++;
  467.     else if (*p == '\\' && p[1] && !((k & 1) && p[1] == '\''))
  468.         p++;
  469.     if ((i & 1) || (j & 1) || (k & 1) || l) {
  470.     instring = (j & 1) ? 2 : (k & 1);
  471.     addx(&tmp);
  472.     if (!addedx) {
  473.         tmp = (char *)line;
  474.         if (i & 1) {
  475.         line = (unsigned char *)dupstring((char *)line);
  476.         strcpy((char *)line, (char *)tmp);
  477.         } else
  478.         line = (unsigned char *)dupstring((char *)line);
  479.     }
  480.     for (p = (char *)line; *p; p++)
  481.         if (*p == '"' || *p == '\'')
  482.         *p = ' ';
  483.         else if ((*p == '(' && p[1] == '(') || (*p == ')' && p[1] == ')'))
  484.         *p = p[1] = ' ', p++;
  485.     } else
  486.     addx(&tmp);
  487.     if (i & 1) {
  488.     if (tmp)
  489.         q += (char *)line - tmp;
  490.     for (p = q + strlen(q); p > q; p--)
  491.         p[1] = *p;
  492.     *q++ = '$';
  493.     *q = '(';
  494.     cs++;
  495.     ll++;
  496.     inc = 1;
  497.     }
  498.     linptr = (char *)line;
  499.     q = NULL;
  500.   start:
  501.     lincmd = incmdpos;
  502.     linredir = inredir;
  503.     cmdstr = NULL;
  504.     zleparse = 1;
  505.     clwpos = -1;
  506.     lexsave();
  507.     hungets(" ");        /* KLUDGE! */
  508.     hungets(UTOSCP(linptr));
  509.     strinbeg();
  510.     pushheap();
  511.     heapalloc();
  512.     i = tt0 = cp = rd = 0;
  513.  
  514.     do {
  515.     lincmd = incmdpos;
  516.     linredir = inredir;
  517.     ctxtlex();
  518.     if (tok == DINBRACK)
  519.         im |= 1;
  520.     else if (tok == DOUTBRACK)
  521.         im &= ~1;
  522.     else if (tok == DINPAR)
  523.         im |= 2;
  524.     else if (tok == DOUTPAR)
  525.         im &= ~2;
  526.  
  527.     if (tok == ENDINPUT)
  528.         break;
  529.     if (tok == BAR || tok == AMPER || tok == BARAMP ||
  530.         tok == DBAR || tok == DAMPER)
  531.         if (tt)
  532.         break;
  533.         else
  534.         i = tt0 = cp = rd = 0;
  535.     if (lincmd && tok == STRING)
  536.         cmdstr = dupstring(tokstr), i = 0;
  537.     if (!zleparse && !tt0) {
  538.         tt = tokstr ? dupstring(tokstr) : NULL;
  539.         if (addedx && tt)
  540.         chuck(tt + cs - wb - 1);
  541.         tt0 = tok;
  542.         clwpos = i;
  543.         cp = lincmd;
  544.         rd = linredir;
  545.     }
  546.     if (!tokstr)
  547.         continue;
  548.     if (i + 1 == clwsize) {
  549.         clwords = (char **)realloc(clwords, (clwsize *= 2) * sizeof(char *));
  550.         memset((vptr) (clwords + i), 0, (clwsize / 2) * sizeof(char *));
  551.     }
  552.     zsfree(clwords[i]);
  553.     clwords[i] = ztrdup(tokstr);
  554.     sl = strlen(tokstr);
  555.     while (sl && clwords[i][sl - 1] == ' ')
  556.         clwords[i][--sl] = '\0';
  557.     if (clwpos == i++ && addedx)
  558.         chuck(&clwords[i-1][((cs-wb-1) >= sl) ? (sl-1) : (cs-wb-1)]);
  559.     }
  560.     while (tok != LEXERR && tok != ENDINPUT &&
  561.        (tok != SEPER || (zleparse && !tt0)));
  562.     clwnum = (tt || !i) ? i : i - 1;
  563.     zsfree(clwords[clwnum]);
  564.     clwords[clwnum] = NULL;
  565.     t0 = tt0;
  566.     lincmd = cp;
  567.     linredir = rd;
  568.  
  569.     if (!t0 || t0 == ENDINPUT) {
  570.     s = ztrdup("");
  571.     we = wb = cs;
  572.     clwpos = clwnum;
  573.     t0 = STRING;
  574.     } else if (t0 == STRING) {
  575.     s = ztrdup(clwords[clwpos]);
  576.     } else if (t0 == ENVSTRING) {
  577.     for (s = tt; *s && *s != '='; s++, wb++);
  578.     if (*s) {
  579.         s++;
  580.         wb++;
  581.         t0 = STRING;
  582.         s = ztrdup(s);
  583.         inwhat = IN_ENV;
  584.     }
  585.     lincmd = 1;
  586.     }
  587.     hflush();
  588.     strinend();
  589.     errflag = zleparse = 0;
  590.     if (addedx)
  591.     wb++;
  592.     if (we > ll)
  593.     we = ll;
  594.     if (im & 2) {
  595.     if (tokstr) {
  596.         *tokstr = ' ';
  597.         if (addedx)
  598.         tokstr[cs - wb + 1] = '\0';
  599.         s = ztrdup(tokstr);
  600.     } else
  601.         s = ztrdup("");
  602.     if (tmp)
  603.         line = (unsigned char *)tmp;
  604.     goto check;
  605.     }
  606.     if (t0 == LEXERR && parbegin != -1) {
  607.     if (opb == parbegin) {
  608.         if (inc)
  609.         cs--, ll--, inc = 0;
  610.         if (tmp)
  611.         line = (unsigned char *)tmp;
  612.         feep();
  613.         noaliases = 0;
  614.         permalloc();
  615.         return NULL;
  616.     }
  617.     opb = parbegin;
  618.     linptr += ll + 1 - parbegin;
  619.     popheap();
  620.     permalloc();
  621.     lexrestore();
  622.     if (inc)
  623.         cs--, ll--, inc = 0;
  624.     goto start;
  625.     }
  626.     if (inc)
  627.     cs--, ll--, inc = 0;
  628.     tt = (char *) line;
  629.     if (tmp)
  630.     line = (unsigned char *)tmp;
  631.     if (t0 != STRING) {
  632.     if (tmp) {
  633.         tmp = NULL;
  634.         linptr = (char *)line;
  635.         popheap();
  636.         permalloc();
  637.         lexrestore();
  638.         goto start;
  639.     }
  640.     feep();
  641.     noaliases = 0;
  642.     permalloc();
  643.     return NULL;
  644.     }
  645.     else if (clwords[clwpos] && clwords[clwpos][0]) {
  646.     for (p = clwords[clwpos]; *p; p++)
  647.         if ((*p == String || *p == Equals || *p == Inang || *p == Outang) &&
  648.         p[1] == Inpar)
  649.         break;
  650.     if (*p && cs > p - clwords[clwpos]) {
  651.         for (q = clwords[clwpos] + we - wb; q > p; q--)
  652.         if (*q == Outpar)
  653.             break;
  654.         if (q > p && cs - wb <= q - clwords[clwpos]) {
  655.         if (!tmp) {
  656.             tmp = (char *) line;
  657.             tt = dupstring((char *) line);
  658.         }
  659.         line = (unsigned char *) tt;
  660.         line[wb + q - clwords[clwpos] + addedx] = '\0';
  661.         linptr = (char *) line;
  662.         ll = strlen(line) - 1;
  663.         popheap();
  664.         permalloc();
  665.         lexrestore();
  666.         q = NULL;
  667.         goto start;
  668.         }
  669.         q = NULL;
  670.     }
  671.     }
  672.  
  673.   check:
  674.  
  675.     if (q)
  676.     wb--, we--;
  677.  
  678.     noaliases = 0;
  679.  
  680.     inwhat = (im & 1) ? IN_COND : (inwhat == IN_ENV ? IN_ENV : IN_NOTHING);
  681.     im &= ~1;
  682.  
  683.  /* check if we are in a mathematical expression */
  684.  
  685.     if (!im) {
  686.     for (tt = s + cs - wb; tt > s && *tt != Inbrack; tt--);
  687.     if (*tt == Inbrack) {
  688.         if (tt[-1] == String)
  689.         im = 1;
  690.         else {
  691.         for (p = tt - 1; p > s && (ialnum(*p) || *p == '_'); p--);
  692.         if (*p == String || (*p == Inbrace && p > s && p[-1] == String))
  693.             im = 1;
  694.         else if (*p == Outpar) {
  695.             for (i = 1, p--; p >= s && i; p--)
  696.             if (*p == Outpar)
  697.                 i++;
  698.             else if (*p == Inpar)
  699.                 i--;
  700.             if (!i && ((p >= s && *p == String) ||
  701.                    (p > s && *p == Inbrack && p[-1] == String)))
  702.             im = 1;
  703.         }
  704.         }
  705.         if (im) {
  706.         for (i = 1, p = tt + 1; *p && i; p++)
  707.             if (*p == Inbrack)
  708.             i++;
  709.             else if (*p == Outbrack)
  710.             i--;
  711.         if (cs - wb >= p - s)
  712.             im = 0;
  713.         }
  714.     }
  715.     }
  716.     if (im) {
  717.     inwhat = IN_MATH;
  718.     for (p = s + cs - wb - 1; p >= s && (ialnum(*p) || *p == '_'); p--);
  719.     if (++p > s) {
  720.         strcpy(s, p);
  721.         wb += p - s - ((im & 2) ? 1 : 0);
  722.     }
  723.     for (p = s; *p && (ialnum(*p) || *p == '_'); p++);
  724.     if (p > s && addedx && *p)
  725.         p--;
  726.     *p = '\0';
  727.     we = wb + p - s;
  728.     }
  729.  
  730.     qword = ztrdup(s);
  731.     for (p = s, tt = qword, i = wb; *p; p++, tt++, i++)
  732.     if (INULL(*p)) {
  733.         if (p[1] || *p != Bnull) {
  734.         if (*p == Bnull)
  735.             *tt = '\\';
  736.         else {
  737.             ocs = cs;
  738.             cs = i;
  739.             foredel(1);
  740.             chuck(tt--);
  741.             if ((cs = ocs) >= i--)
  742.             cs--;
  743.             we--;
  744.         }
  745.         }
  746.         else {
  747.         ocs = cs;
  748.         *tt = '\0';
  749.         cs = we;
  750.         backdel(1);
  751.         if (ocs == we)
  752.             cs = we - 1;
  753.         else
  754.             cs = ocs;
  755.         we--;
  756.         }
  757.         chuck(p--);
  758.     }
  759.  
  760.     if (unset(NOBANGHIST)) {
  761.     q = tt = ncalloc(2*strlen(qword) + 1);
  762.     for (p = qword; *p; p++) {
  763.         if (*p == (char) bangchar)
  764.         *q++ = '\\'; /*, wb--, cs--;*/
  765.         *q++ = *p;
  766.     }
  767.     *q = '\0';
  768.     zsfree(qword);
  769.     qword = ztrdup(tt);
  770.     }
  771.     ll = strlen(line);
  772.     permalloc();
  773.  
  774.     return (char *)s;
  775. }
  776.  
  777. void doexpansion(s, lst, explincmd)    /**/
  778. char *s;
  779. int lst;
  780. int explincmd;
  781. {
  782.     Lklist vl = newlist();
  783.     char *ss;
  784.  
  785.     pushheap();
  786.     addnode(vl, s);
  787.     prefork(vl, 0);
  788.     if (errflag)
  789.     goto end;
  790.     postfork(vl, (lst == COMP_LIST_EXPAND) || (lst == COMP_EXPAND));
  791.     if (errflag)
  792.     goto end;
  793.     if (empty(vl) || !*(char *)peekfirst(vl)) {
  794.     if (!noerrs)
  795.         feep();
  796.     goto end;
  797.     }
  798.     if (lst == COMP_LIST_EXPAND) {
  799.     listlist(vl);
  800.     goto end;
  801.     } else if (peekfirst(vl) == (vptr) s ||
  802.            (!nextnode(firstnode(vl)) && *s == Tilde &&
  803.         (ss = dupstring(s), filesubstr(&ss, 0)) &&
  804.         !strcmp(ss, (char *)peekfirst(vl)))) {
  805.     if (lst == COMP_EXPAND_COMPLETE)
  806.         docompletion(s, COMP_COMPLETE, explincmd);
  807.     else
  808.         feep();
  809.     goto end;
  810.     }
  811.     cs = wb;
  812.     foredel(we - wb);
  813.     while ((ss = (char *)ugetnode(vl))) {
  814.     untokenize(ss);
  815.     ss = quotename(ss, NULL, NULL, NULL);
  816.     inststr(ss);
  817. #if 0
  818.     if (full(vl)) {
  819.         spaceinline(1);
  820.         line[cs++] = ' ';
  821.     }
  822. #endif
  823.     spaceinline(1);
  824.     line[cs++] = ' ';
  825.     }
  826.   end:
  827.     popheap();
  828. }
  829.  
  830. void gotword(s)            /**/
  831. char *s;
  832. {
  833.     we = ll + 1 - inbufct;
  834.     if (cs <= we) {
  835.     wb = ll - wordbeg;
  836.     zleparse = 0;
  837.     /* major hack ahead */
  838.     if (wb && line[wb] == '!' && line[wb - 1] == '\\')
  839.         wb--;
  840.     }
  841. }
  842.  
  843. void inststrlen(str, move, len)    /**/
  844. char *str;
  845. int move;
  846. int len;
  847. {
  848.     if (!len)
  849.     return;
  850.     if (len == -1)
  851.     len = strlen(str);
  852.     spaceinline(len);
  853.     strncpy((char *)(line + cs), str, len);
  854.     if (move)
  855.     cs += len;
  856. }
  857.  
  858. char *quotename(s, e, te, pl)    /**/
  859. char *s;
  860. char **e;
  861. char **te;
  862. int *pl;
  863. {
  864.     char *tt, *v, *u, buf[MAXPATHLEN*2];
  865.     int sf = 0;
  866.  
  867.     tt = v = buf;
  868.     u = s;
  869.     for (; *u; u++) {
  870.     if (e && *e == u)
  871.         *e = v, sf |= 1;
  872.     if (te && *te == u)
  873.         *pl = v - tt, sf |= 2;
  874.     if (ispecial(*u) &&
  875.         (!instring || (!isset(NOBANGHIST) &&
  876.                *u == (char)bangchar) ||
  877.          (instring == 2 &&
  878.           (*u == '$' || *u == '`' || *u == '\"')) ||
  879.          (instring == 1 && *u == '\'')))
  880.         if (*u == '\n' || (instring == 1 && *u == '\'')) {
  881.         *v++ = '\'';
  882.         if (*u == '\'')
  883.             *v++ = '\\';
  884.         *v++ = *u;
  885.         *v++ = '\'';
  886.         continue;
  887.         } else
  888.         *v++ = '\\';
  889.     *v++ = *u;
  890.     }
  891.     *v = '\0';
  892.     if (strcmp(buf, s))
  893.     tt = dupstring(buf);
  894.     else
  895.     tt = s;
  896.     v += tt - buf;
  897.     if (e && (sf & 1))
  898.     *e += tt - buf;
  899.     if (te && (sf & 2))
  900.     *te += tt - buf;
  901.     
  902.     if (e && *e == u)
  903.     *e = v;
  904.     if (te && *te == u)
  905.     *pl = v - tt;
  906.  
  907.     return tt;
  908. }
  909.  
  910. void addmatch(s, t)        /**/
  911. char *s;
  912. char *t;
  913. {
  914.     int test = 0, sl = strlen(s), pl = rpl, cc = 0;
  915.     char sav = 0, *e = NULL, *tt, *te, *fc;
  916.     Comp cp = patcomp;
  917.     Param pm;
  918.  
  919.     if (!addwhat)
  920.     test = 1;
  921.     else if (addwhat == -1 || addwhat == -5 || addwhat == -6 ||
  922.          addwhat == CC_FILES || addwhat == -7 || addwhat == -8) {
  923.     if (sl < fpl + fsl)
  924.         return;
  925.  
  926.     if ((addwhat == CC_FILES ||
  927.          addwhat == -5) && !*psuf && !*fsuf) {
  928.         char **pt = fignore;
  929.         int filell;
  930.  
  931.         for (test = 1; test && *pt; pt++)
  932.         if ((filell = strlen(*pt)) < sl
  933.             && !strcmp(*pt, s + sl - filell))
  934.             test = 0;
  935.  
  936.         if (!test)
  937.         return;
  938.     }
  939.     pl = fpl;
  940.     if (addwhat == -5 || addwhat == -8) {
  941.         test = 1;
  942.         cp = filecomp;
  943.         cc = cp || ispattern;
  944.         e = s + sl - fsl;
  945.     }
  946.     else {
  947.         if ((cp = filecomp)) {
  948.         if ((test = domatch(s, filecomp, 0)))
  949.             cc = 1;
  950.         } else {
  951.         e = s + sl - fsl;
  952.         if ((test = !strncmp(s, fpre, fpl)))
  953.             test = !strcmp(e, fsuf);
  954.         if (ispattern)
  955.             cc = 1;
  956.         }
  957.     }
  958.     if (test) {
  959.         fc = NULL;
  960.         if (addwhat == -7 && ISEXCMD(((Cmdnam) t)->flags) && 
  961.         !(fc = findcmd(s)))
  962.         return;
  963.         if (fc)
  964.         zsfree(fc);
  965.         haswhat |= HAS_FILES;
  966.  
  967.         if (addwhat == CC_FILES || addwhat == -6 ||
  968.         addwhat == -5 || addwhat == -8) {
  969.         te = s + pl;
  970.         s = quotename(s, &e, &te, &pl);
  971.         sl = strlen(s);
  972.         } else if (!cc) {
  973.         s = dupstring(t = s);
  974.         e += s - t;
  975.         }
  976.         if (cc) {
  977.         tt = (char *)halloc(strlen(ppre) + strlen(psuf) + sl + 1);
  978.         strcpy(tt, ppre);
  979.         strcat(tt, s);
  980.         strcat(tt, psuf);
  981.         untokenize(s = tt);
  982.         }
  983.     }
  984.     } else if (addwhat == -2 ||
  985.            (addwhat == -3 && !(((Cmdnam) t)->flags & DISABLED)) ||
  986.            (addwhat == -4 && (pm = (Param) t) && (pmtype(pm) == PMFLAG_s) &&
  987.            (tt = pm->gets.cfn(pm)) && *tt == '/') ||
  988.            (addwhat > 0 &&
  989.         (((addwhat & CC_ARRAYS) && (((Param) t)->flags & PMFLAG_A)) ||
  990.          ((addwhat & CC_INTVARS) && (((Param) t)->flags & PMFLAG_i)) ||
  991.          ((addwhat & CC_ENVVARS) && (((Param) t)->flags & PMFLAG_x)) ||
  992.          ((addwhat & CC_SCALARS) &&
  993.          !(((Param) t)->flags & (PMFLAG_A | PMFLAG_i))) ||
  994.          ((addwhat & CC_READONLYS) && (((Param) t)->flags & PMFLAG_r)) ||
  995.          ((addwhat & CC_SPECIALS) && (((Param) t)->flags & PMFLAG_SPECIAL)) ||
  996.          ((addwhat & CC_PARAMS) && !(((Param) t)->flags & PMFLAG_x)) ||
  997.          ((addwhat & CC_FUNCS) && (((Cmdnam) t)->flags & SHFUNC)) ||
  998.          ((addwhat & CC_BUILTINS) && (((Cmdnam) t)->flags & BUILTIN) &&
  999.           !(((Cmdnam) t)->flags & EXCMD)) ||
  1000.          ((addwhat & CC_DISCMDS) && (((Cmdnam) t)->flags & DISABLED)) ||
  1001.          ((addwhat & CC_EXCMDS) && (((Cmdnam) t)->flags & EXCMD)) ||
  1002.          ((addwhat & CC_ALREG) && (((Alias) t)->cmd) == 1) ||
  1003.          ((addwhat & CC_ALGLOB) && !(((Alias) t)->cmd))))) {
  1004.     if (sl >= rpl + rsl) {
  1005.         if (cp)
  1006.         test = domatch(s, patcomp, 0);
  1007.         else {
  1008.         e = s + sl - rsl;
  1009.         if ((test = !strncmp(s, rpre, rpl)))
  1010.             test = !strcmp(e, rsuf);
  1011.         }
  1012.     }
  1013.     if (!test && sl < lpl + lsl)
  1014.         return;
  1015.     if (!test && !noreal && sl >= lpl + lsl) {
  1016.         e = s + sl - lsl;
  1017.         if ((test = !strncmp(s, lpre, lpl)))
  1018.         test = !strcmp(e, lsuf);
  1019.         pl = lpl;
  1020.     }
  1021.     if (test)
  1022.         haswhat |= HAS_MISC;
  1023.     }
  1024.     if (!test)
  1025.     return;
  1026.  
  1027.     t = s += (ispattern ? 0 : pl);
  1028.     e += t - s;
  1029.     s = t;
  1030.  
  1031.     if (ispattern)
  1032.     e = NULL, sav = '\0';
  1033.     else {
  1034.     if ((sav = *e)) {
  1035.         *e = '\0';
  1036.         t = dupstring(t);
  1037.     }
  1038.     }
  1039.  
  1040.     if (!ispattern && firstm) {
  1041.     if ((test = pfxlen(firstm, s)) < ab)
  1042.         ab = test;
  1043.     if ((test = sfxlen(firstm, s)) < ae)
  1044.         ae = test;
  1045.     }
  1046.  /* If we are doing a glob completion we store the whole string in
  1047.      * the list. Otherwise only the part that fits between the prefix
  1048.      * and the suffix is stored. */
  1049.  
  1050.     addnode(matches, t);
  1051.     if (!firstm)
  1052.     firstm = t, ab = ae = shortl = 100000;
  1053.     if (!ispattern && (sl = strlen(t)) < shortl)
  1054.     shortl = sl, shortest = t;
  1055.     if (sav)
  1056.     *e = sav;
  1057. }
  1058.  
  1059. #ifdef HAS_NIS
  1060. static int match_username(status, key, keylen, val, vallen, data)
  1061. int status;
  1062. char *key, *val;
  1063. int keylen, vallen;
  1064. dopestring *data;
  1065. {
  1066.     if (errflag || status != YP_TRUE)
  1067.     return 1;
  1068.  
  1069.     if (vallen > keylen && val[keylen] == ':') {
  1070.     val[keylen] = '\0';
  1071.     addmatch(dupstring(val), NULL);
  1072.     }
  1073.     return 0;
  1074. }
  1075.  
  1076. #endif
  1077.  
  1078. void maketildelist()        /**/
  1079. {
  1080.     int i;
  1081.  
  1082. #ifdef HAS_NIS
  1083.     char domain[YPMAXDOMAIN];
  1084.     struct ypall_callback cb;
  1085.     dopestring data;
  1086.     FILE *pwf;
  1087.     char buf[BUFSIZ], *p;
  1088.     int skipping;
  1089.  
  1090.     data.s = fpre;
  1091.     data.len = fpl;
  1092.  /* Get potential matches from NIS and cull those without local accounts */
  1093.     if (getdomainname(domain, YPMAXDOMAIN) == 0) {
  1094.     cb.foreach = (int((*)())) match_username;
  1095.     cb.data = (char *)&data;
  1096.     yp_all(domain, PASSWD_MAP, &cb);
  1097. /*    for (n = firstnode(matches); n; incnode(n))
  1098.         if (getpwnam(getdata(n)) == NULL)
  1099.         uremnode(matches, n);*/
  1100.     }
  1101.  /* Don't forget the non-NIS matches from the flat passwd file */
  1102.     if ((pwf = fopen(PASSWD_FILE, "r")) != NULL) {
  1103.     skipping = 0;
  1104.     while (fgets(buf, BUFSIZ, pwf) != NULL) {
  1105.         if (strchr(buf, '\n') != NULL) {
  1106.         if (!skipping) {
  1107.             if ((p = strchr(buf, ':')) != NULL) {
  1108.             *p = '\0';
  1109.             addmatch(dupstring(buf), NULL);
  1110.             }
  1111.         } else
  1112.             skipping = 0;
  1113.         } else
  1114.         skipping = 1;
  1115.     }
  1116.     fclose(pwf);
  1117.     }
  1118. #else
  1119.     struct passwd *tmppwd;
  1120.  
  1121. #ifdef CACHE_USERNAMES
  1122.     static int usernamescached = 0;
  1123.  
  1124.     if (!usernamescached) {
  1125.     setpwent();
  1126.     while ((tmppwd = getpwent()) != NULL && !errflag)
  1127.         adduserdir(dupstring(tmppwd->pw_name), tmppwd->pw_dir, 1, 1);
  1128.     endpwent();
  1129.     usernamescached = 1;
  1130.     }
  1131. #else
  1132.     setpwent();
  1133.     while ((tmppwd = getpwent()) != NULL && !errflag)
  1134.     addmatch(dupstring(tmppwd->pw_name), NULL);
  1135.     endpwent();
  1136.  
  1137.     if (addwhat != -1)
  1138.     return;
  1139. #endif
  1140. #endif
  1141.  
  1142.     for (i = 0; i < userdirct; i++)
  1143.     if (addwhat == -1 || namdirs[i].homedir)
  1144.         addmatch(namdirs[i].name, NULL);
  1145. }
  1146.  
  1147. char *rembslash(s)    /**/
  1148. char *s;
  1149. {
  1150.     char *t = s = dupstring(s);
  1151.  
  1152.     while (*s)
  1153.     if (*s == '\\') {
  1154.         chuck(s);
  1155.         if (*s) s++;
  1156.     }
  1157.     else
  1158.         s++;
  1159.  
  1160.     return t;
  1161. }
  1162.  
  1163. int getcpat(str, cpatindex, cpat, class)    /**/
  1164. char *str;
  1165. int cpatindex;
  1166. char *cpat;
  1167. int class;
  1168. {
  1169.     char *s, *t, *p;
  1170.     int d = 0;
  1171.  
  1172.     if (!str || !*str)
  1173.     return -1;
  1174.  
  1175.     cpat = rembslash(cpat);
  1176.  
  1177.     str = ztrdup(str);
  1178.     untokenize(str);
  1179.     if (!cpatindex)
  1180.     cpatindex++, d = 0;
  1181.     else if ((d = (cpatindex < 0)))
  1182.     cpatindex = -cpatindex;
  1183.  
  1184.     for (s = d ? str + strlen(str) - 1 : str;
  1185.      d ? (s >= str) : *s;
  1186.      d ? s-- : s++) {
  1187.     for (t = s, p = cpat; *t && *p; p++) {
  1188.         if (class) {
  1189.         if (*p == *s && !--cpatindex) {
  1190.             zsfree(str);
  1191.             return (int)(s - str + 1);
  1192.         }
  1193.         } else if (*t++ != *p)
  1194.         break;
  1195.     }
  1196.     if (!class && !*p && !--cpatindex) {
  1197.         zsfree(str);
  1198.         return (int)(t - str);
  1199.     }
  1200.     }
  1201.     zsfree(str);
  1202.     return -1;
  1203. }
  1204.  
  1205. Compctl ccmain;
  1206.  
  1207. Compctl get_ccompctl(occ, compadd, incmd)  /**/
  1208. Compctl occ;
  1209. int *compadd;
  1210. int incmd;
  1211. {
  1212.     Compctl compc, ret;
  1213.     Compctlp ccp;
  1214.     int t, i, a, b, tt, ra = 0, rb = 0, j;
  1215.     Compcond or, cc;
  1216.     char *s, *ss, *sc = NULL;
  1217.     Comp comp;
  1218.  
  1219.     *compadd = 0;
  1220.  
  1221.     if (!(ret = compc = occ)) {
  1222.     if (inwhat == IN_ENV)
  1223.         ret = &cc_default;
  1224.     else if (inwhat == IN_MATH) {
  1225.         cc_dummy.mask = CC_PARAMS;
  1226.         ret = &cc_dummy;
  1227.         cc_dummy.refc = 10000;
  1228.     } else if (inwhat == IN_COND) {
  1229.         s = clwpos ? clwords[clwpos - 1] : "";
  1230.         cc_dummy.mask = !strcmp("-o", s) ? CC_OPTIONS :
  1231.         ((*s == '-' && s[1] && !s[2]) ||
  1232.          !strcmp("-nt", s) ||
  1233.          !strcmp("-ot", s) ||
  1234.          !strcmp("-ef", s)) ? CC_FILES :
  1235.              (CC_FILES | CC_PARAMS);
  1236.         ret = &cc_dummy;
  1237.         cc_dummy.refc = 10000;
  1238.     } else if (incmd)
  1239.         ret = &cc_compos;
  1240.     else if (linredir || 
  1241.          !(cmdstr &&
  1242.            (((ccp = (Compctlp)gethnode(cmdstr, compctltab)) &&
  1243.              (compc = ret = ccp->cc)) ||
  1244.             ((s = dupstring(cmdstr)) && remlpaths(&s) &&
  1245.              (ccp = (Compctlp) gethnode(s, compctltab)) &&
  1246.              (compc = ret = ccp->cc)))))
  1247.         ret = &cc_default;
  1248.  
  1249.     ccmain = compc = ret;
  1250.     ccmain->refc++;
  1251.     }
  1252.  
  1253.     if (compc && compc->ext) {
  1254.     compc = compc->ext;
  1255.     for (t = 0; compc && !t; compc = compc->next) {
  1256.         for (cc = compc->cond; cc && !t; cc = or) {
  1257.         or = cc->or;
  1258.         for (t = 1; cc && t; cc = cc->and) {
  1259.             for (t = i = 0; i < cc->n && !t; i++) {
  1260.             s = NULL;
  1261.             ra = 0;
  1262.             rb = clwnum - 1;
  1263.             switch (cc->type) {
  1264.             case CCT_POS:
  1265.                 tt = clwpos;
  1266.                 goto cct_num;
  1267.             case CCT_NUMWORDS:
  1268.                 tt = clwnum;
  1269.               cct_num:
  1270.                 if ((a = cc->u.r.a[i]) < 0)
  1271.                 a += clwnum;
  1272.                 if ((b = cc->u.r.b[i]) < 0)
  1273.                 b += clwnum;
  1274.                 if (cc->type == CCT_POS)
  1275.                 ra = a, rb = b;
  1276.                 t = (tt >= a && tt <= b);
  1277.                 break;
  1278.             case CCT_CURSUF:
  1279.             case CCT_CURPRE:
  1280.                 s = ztrdup(clwpos < clwnum ? clwords[clwpos] : "");
  1281.                 untokenize(s);
  1282.                 sc = rembslash(cc->u.s.s[i]);
  1283.                 a = strlen(sc);
  1284.                 if (!strncmp(s, sc,a)) {
  1285.                 *compadd = (cc->type == CCT_CURSUF ? a : 0);
  1286.                 t = 1;
  1287.                 }
  1288.                 break;
  1289.             case CCT_CURSUB:
  1290.             case CCT_CURSUBC:
  1291.                 if (clwpos < 0 || clwpos > clwnum)
  1292.                 t = 0;
  1293.                 else {
  1294.                 if ((a = getcpat(clwords[clwpos],
  1295.                          cc->u.s.p[i],
  1296.                          cc->u.s.s[i],
  1297.                          cc->type == CCT_CURSUBC)) != -1)
  1298.                     *compadd = a, t = 1;
  1299.                 }
  1300.                 break;
  1301.  
  1302.             case CCT_CURPAT:
  1303.             case CCT_CURSTR:
  1304.                 tt = clwpos;
  1305.                 goto cct_str;
  1306.             case CCT_WORDPAT:
  1307.             case CCT_WORDSTR:
  1308.                 tt = 0;
  1309.               cct_str:
  1310.                 if ((a = tt + cc->u.s.p[i]) < 0)
  1311.                 a += clwnum;
  1312.                 s = ztrdup((a < 0 || a >= clwnum) ? "" : clwords[a]);
  1313.                 untokenize(s);
  1314.  
  1315.                 if (cc->type == CCT_CURPAT || cc->type == CCT_WORDPAT) {
  1316.                 tokenize(ss = dupstring(cc->u.s.s[i]));
  1317.                 t = ((comp = parsereg(ss)) && domatch(s, comp, 0));
  1318.                 } else
  1319.                 t = (!strcmp(s, rembslash(cc->u.s.s[i])));
  1320.                 break;
  1321.             case CCT_RANGESTR:
  1322.             case CCT_RANGEPAT:
  1323.                 if (cc->type == CCT_RANGEPAT)
  1324.                 tokenize(sc = dupstring(cc->u.l.a[i]));
  1325.                 for (j = clwpos; j; j--) {
  1326.                 untokenize(s = ztrdup(clwords[j]));
  1327.                 if (cc->type == CCT_RANGESTR)
  1328.                     sc = rembslash(cc->u.l.a[i]);
  1329.                 if (cc->type == CCT_RANGESTR ?
  1330.                     !strncmp(s, sc, strlen(sc)) :
  1331.                     ((comp = parsereg(sc)) &&
  1332.                      domatch(s, comp, 0))) {
  1333.                     zsfree(s);
  1334.                     ra = j + 1;
  1335.                     t = 1;
  1336.                     break;
  1337.                 }
  1338.                 zsfree(s);
  1339.                 }
  1340.                 if (t) {
  1341.                 if (cc->type == CCT_RANGEPAT)
  1342.                     tokenize(sc = dupstring(cc->u.l.b[i]));
  1343.                 for (j++; j < clwnum; j++) {
  1344.                     untokenize(s = ztrdup(clwords[j]));
  1345.                     if (cc->type == CCT_RANGESTR)
  1346.                     sc = rembslash(cc->u.l.b[i]);
  1347.                     if (cc->type == CCT_RANGESTR ?
  1348.                     !strncmp(s, sc, strlen(sc)) :
  1349.                     ((comp = parsereg(sc)) &&
  1350.                      domatch(s, comp, 0))) {
  1351.                     zsfree(s);
  1352.                     rb = j - 1;
  1353.                     t = clwpos <= rb;
  1354.                     break;
  1355.                     }
  1356.                     zsfree(s);
  1357.                 }
  1358.                 }
  1359.                 s = NULL;
  1360.             }
  1361.             zsfree(s);
  1362.             }
  1363.         }
  1364.         }
  1365.         if (t)
  1366.         break;
  1367.     }
  1368.     if (compc)
  1369.         ret = compc;
  1370.     }
  1371.     if (ret->subcmd) {
  1372.     char **ow = clwords, *os = cmdstr, *ops = NULL;
  1373.     int oldn = clwnum, oldp = clwpos;
  1374.  
  1375.     if (ra < 1)
  1376.         ra = 1;
  1377.     if (ra >= clwnum)
  1378.         ra = clwnum - 1;
  1379.     if (rb < 1)
  1380.         rb = 1;
  1381.     if (rb >= clwnum)
  1382.         rb = clwnum - 1;
  1383.  
  1384.     clwnum = rb - ra + 1;
  1385.     clwpos = clwpos - ra;
  1386.     if (ret->subcmd[0]) {
  1387.         clwnum++;
  1388.         clwpos++;
  1389.         incmd = 0;
  1390.         ops = clwords[ra - 1];
  1391.         clwords[ra - 1] = cmdstr = ret->subcmd;
  1392.         clwords += ra - 1;
  1393.     } else {
  1394.         cmdstr = clwords[ra];
  1395.         incmd = !clwpos;
  1396.         clwords += ra;
  1397.     }
  1398.     *compadd = 0;
  1399.     if (ccmain != &cc_dummy)
  1400.         freecompctl(ccmain);
  1401.     ret = get_ccompctl(NULL, compadd, incmd);
  1402.     clwords = ow;
  1403.     cmdstr = os;
  1404.     clwnum = oldn;
  1405.     clwpos = oldp;
  1406.     if (ops)
  1407.         clwords[ra - 1] = ops;
  1408.     }
  1409.     return ret;
  1410. }
  1411.  
  1412. void dumphtable(ht, what)    /**/
  1413. Hashtab ht;
  1414. int what;
  1415. {
  1416.     int t0;
  1417.     struct hashnode *hn;
  1418.  
  1419.     addwhat = what;
  1420.  
  1421.     for (t0 = ht->hsize - 1; t0 >= 0; t0--)
  1422.     for (hn = ht->nodes[t0]; hn; hn = hn->next)
  1423.         addmatch(hn->nam, (char *)hn);
  1424.  
  1425. }
  1426.  
  1427. char *getreal(str)    /**/
  1428. char *str;
  1429. {
  1430.     Lklist l = newlist();
  1431.     int ne = noerrs;
  1432.  
  1433.     noerrs = 1;
  1434.     addnode(l, dupstring(str));
  1435.     prefork(l, 0);
  1436.     if (!errflag) {
  1437.     postfork(l, 0);
  1438.     if (!errflag && full(l)) {
  1439.         noerrs = ne;
  1440.         return ztrdup(peekfirst(l));
  1441.     }
  1442.     }
  1443.     errflag = 0;
  1444.     noerrs = ne;
  1445.  
  1446.     return ztrdup(str);
  1447. }
  1448.  
  1449. void gen_matches_files(dirs, execs, all)    /**/
  1450. int dirs;
  1451. int execs;
  1452. int all;
  1453. {
  1454.     DIR *d;
  1455.     struct dirent *de;
  1456.     struct stat buf;
  1457.     char *n, p[MAXPATHLEN], *q = NULL, *e;
  1458.     Lklist l = NULL;
  1459.     int ns = 0, ng = opts[NULLGLOB], test, aw = addwhat;
  1460.  
  1461.     addwhat = execs ? -8 : -5;
  1462.     opts[NULLGLOB] = OPT_SET;
  1463.  
  1464.     if (*psuf) {
  1465.     q = psuf + strlen(psuf) - 1;
  1466.     ns = !(*q == Star || *q == Outpar);
  1467.     l = newlist();
  1468.     dirs = 1;
  1469.     all = execs = 0;
  1470.     }
  1471.     if ((d = opendir((prpre && *prpre) ? prpre : "."))) {
  1472.     if (!all && prpre) {
  1473.         strcpy(p, prpre);
  1474.         q = p + strlen(prpre);
  1475.     }
  1476.     while ((de = readdir(d)) && !errflag) {
  1477.         n = de->d_name;
  1478.         if (n[0] == '.' && (n[1] == '\0' || (n[1] == '.' && n[2] == '\0')))
  1479.         continue;
  1480.         if (*n != '.' || *fpre == '.' || isset(GLOBDOTS)) {
  1481.         if (filecomp)
  1482.             test = domatch(n, filecomp, 0);
  1483.         else {
  1484.             e = n + strlen(n) - fsl;
  1485.             if ((test = !strncmp(n, fpre, fpl)))
  1486.             test = !strcmp(e, fsuf);
  1487.         }
  1488.         if (!test) continue;
  1489.         if (!all) {
  1490.             strcpy(q, n);
  1491.             if (stat(p, &buf) < 0)
  1492.             continue;
  1493.         }
  1494.         if (all ||
  1495.             (dirs && (buf.st_mode & S_IFMT) == S_IFDIR) ||
  1496.             (execs &&
  1497.             ((buf.st_mode & (S_IFMT | S_IEXEC))
  1498.              == (S_IFREG | S_IEXEC)))) {
  1499.             if (*psuf) {
  1500.             int o = strlen(p), tt;
  1501.  
  1502.             strcpy(p + o, psuf);
  1503.  
  1504.             if (ispattern || (ns && isset(GLOBCOMPLETE))) {
  1505.                 if (ns) {
  1506.                 int tl = strlen(p);
  1507.  
  1508.                 p[tl] = Star;
  1509.                 p[tl + 1] = '\0';
  1510.                 }
  1511.                 addnode(l, p);
  1512.                 postfork(l, 1);
  1513.                 tt = full(l);
  1514.                 while (ugetnode(l));
  1515.             } else
  1516.                 tt = !access(p, F_OK);
  1517.  
  1518.             p[o] = '\0';
  1519.             if (tt)
  1520.                 addmatch(dupstring(n), NULL);
  1521.             } else
  1522.             addmatch(dupstring(n), NULL);
  1523.         }
  1524.         }
  1525.     }
  1526.     closedir(d);
  1527.     }
  1528.     opts[NULLGLOB] = ng;
  1529.     addwhat = aw;
  1530. }
  1531.  
  1532. char *expl, *ccsuffix;
  1533. int remsuffix;
  1534.  
  1535. void quotepresuf(ps)        /**/
  1536. char **ps;
  1537. {
  1538.     if (*ps) {
  1539.     char *p = quotename(*ps, NULL, NULL, NULL);
  1540.     if (p != *ps) {
  1541.         zsfree(*ps);
  1542.         *ps = ztrdup(p);
  1543.     }
  1544.     }
  1545. }
  1546.  
  1547. int clearflag;
  1548.  
  1549.  
  1550. void docompletion(s, lst, incmd)/**/
  1551. char *s;
  1552. int lst;
  1553. int incmd;
  1554. {
  1555.     Compctl cc = NULL;
  1556.     int offs, t, sf1, sf2, compadd, isp = 0, ooffs;
  1557.     char *p, *sd = NULL, sav, *tt, *s1, *s2, *os = NULL;
  1558.     int owe = we, owb = wb, ocs = cs, delit;
  1559.     unsigned char *ol = NULL;
  1560.  
  1561.  xorrec:
  1562.  
  1563.     if (unset(COMPLETEINWORD) && cs != we)
  1564.     cs = we;
  1565.     if ((offs = cs - wb) > (t = strlen(s)))
  1566.     offs = t;
  1567.  
  1568.     ispattern = haswhat = lastambig = 0;
  1569.     patcomp = filecomp = NULL;
  1570.     menucur = NULL;
  1571.     shortest = NULL;
  1572.  
  1573.     zsfree(rpre);
  1574.     zsfree(rsuf);
  1575.     zsfree(lpre);
  1576.     zsfree(lsuf);
  1577.     zsfree(ppre);
  1578.     zsfree(psuf);
  1579.     zsfree(prpre);
  1580.     zsfree(fpre);
  1581.     zsfree(fsuf);
  1582.     zsfree(mpre);
  1583.     zsfree(msuf);
  1584.  
  1585.     rpre = rsuf = lpre = lsuf = ppre = psuf = prpre = 
  1586.     fpre = fsuf = mpre = msuf = firstm = NULL;
  1587.  
  1588.     if (!cc) {
  1589.     heapalloc();
  1590.     pushheap();
  1591.     os = dupstring(s);
  1592.     ol = (unsigned char *) dupstring((char *) line);
  1593.     }
  1594.  
  1595.     matches = newlist();
  1596.  
  1597.     if (!cc || cc->ext)
  1598.     cc = get_ccompctl(cc, &compadd, incmd);
  1599.  
  1600.     wb += compadd;
  1601.     s += compadd;
  1602.     if ((offs -= compadd) < 0) {
  1603.     feep();
  1604.     goto compend;
  1605.     }
  1606.  /* insert prefix, if any */
  1607.  
  1608.     if (cc->prefix) {
  1609.     int pl = 0, sl = strlen(cc->prefix);
  1610.  
  1611.     if (*s) {
  1612.         sd = dupstring(s);
  1613.         untokenize(sd);
  1614.         pl = pfxlen(cc->prefix, sd);
  1615.         s += pl;
  1616.     }
  1617.     if (pl < sl) {
  1618.         int savecs = cs;
  1619.  
  1620.         cs = wb + pl;
  1621.         inststrlen(cc->prefix + pl, 0, sl - pl);
  1622.         cs = savecs + sl - pl;
  1623.     }
  1624.     wb += sl;
  1625.     we += sl - pl;
  1626.     }
  1627.     if ((ccsuffix = cc->suffix) && *ccsuffix) {
  1628.     char *sdup = dupstring(ccsuffix);
  1629.     int sl = strlen(sdup), suffixll;
  1630.  
  1631.     for (p = sdup + sl - 1; p >= sdup && *p == ' '; p--, sl--);
  1632.     p[1] = '\0';
  1633.  
  1634.     if (!sd) {
  1635.         sd = dupstring(s);
  1636.         untokenize(sd);
  1637.     }
  1638.     if (*sd && (suffixll = strlen(sd)) >= sl &&
  1639.         !strcmp(sdup, sd + suffixll - sl))
  1640.         ccsuffix = NULL, haswhat |= HAS_SUFFIX, s[suffixll - sl] = '\0';
  1641.     }
  1642.  
  1643.     if ((ic = *s) != Tilde && ic != Equals)
  1644.     ic = '\0';
  1645.     offs = cs - wb;
  1646.     if ((offs = cs - wb) > (t = strlen(s)))
  1647.     offs = t;
  1648.  
  1649.  /* Check if we have to complete a parameter name... */
  1650.  
  1651.     for (p = s + offs; p >= s && *p != String; p--);
  1652.     if (*p == String && p[1] != Inpar && p[1] != Inbrack) {
  1653.     char *b = p + 1, *e = b;
  1654.     int n, br = 1;
  1655.  
  1656.     if (*b == Inbrace)
  1657.         b++, br++;
  1658.  
  1659.     for (t = 0; *b && !t; b++)
  1660.         if (*b == Inpar) {
  1661.         for (n = 1, b++; *b && b < s + offs && n; b++)
  1662.             if (*b == Inpar)
  1663.             n++;
  1664.             else if (*b == Outpar)
  1665.             n--;
  1666.         b--;
  1667.         } else
  1668.         t = ialnum(*b) || *b == '_' || *b == Star || *b == Quest ||
  1669.             *b == Inbrack || *b == Outbrace || *b == '/';
  1670.  
  1671.     for (e = b; *e && t; e++)
  1672.         if (!(ialnum(*e) || *e == '_' || *e == Star || *e == Quest))
  1673.         break;
  1674.  
  1675.     if (offs <= e - s) {
  1676.         if (b > s && b[-1] != String)
  1677.         b--;
  1678.         if (cs == we)
  1679.         complexpect = br;
  1680.         wb += b - s;
  1681.         offs -= b - s;
  1682.         we = wb + e - b;
  1683.         *e = '\0';
  1684.         s = b;
  1685.         isp = 1;
  1686.         cc = ccmain = &cc_dummy;
  1687.         cc_dummy.refc = 10000;
  1688.         cc_dummy.mask = CC_PARAMS | CC_ENVVARS;
  1689.     } else
  1690.         complexpect = 0;
  1691.     }
  1692.  
  1693.     ooffs = offs;
  1694.     if (cc->mask & CC_DELETE) {
  1695.     delit = 1;
  1696.     *s = '\0';
  1697.     offs = 0;
  1698.     }
  1699.     else
  1700.     delit = 0;
  1701.  
  1702.  /* compute line prefix/suffix */
  1703.  
  1704.     sav = s[offs];
  1705.     s[offs] = '\0';
  1706.     p = quotename(s, NULL, NULL, NULL);
  1707.     if (strcmp(p, s) && !strpfx(p, qword)) {
  1708.     int l1, l2;
  1709.  
  1710.     backdel(l1 = cs - wb);
  1711.     untokenize(p);
  1712.     inststrlen(p, 1, l2 = strlen(p));
  1713.     we += l2-1l;
  1714.     }
  1715.     lpre = ztrdup(s);
  1716.     s[offs] = sav;
  1717.     if (s[offs] &&
  1718.     (p = quotename(s + offs, NULL, NULL, NULL)) &&
  1719.     (strcmp(p, s + offs) && !strsfx(p, qword))) {
  1720.     int l1, l2;
  1721.  
  1722.     foredel(l1 = strlen(s + offs));
  1723.     untokenize(p);
  1724.     inststrlen(p, 0, l2 = strlen(p));
  1725.     we += l2-l1;
  1726.     }
  1727.     lsuf = ztrdup(s + offs);
  1728.  
  1729.  /* first check for ~... and =... */
  1730.  
  1731.     if (ic) {
  1732.     for (p = lpre + strlen(lpre); p > lpre; p--)
  1733.         if (*p == '/')
  1734.         break;
  1735.  
  1736.     if (*p == '/')
  1737.         ic = 0;
  1738.     }
  1739.  /* compute real prefix/suffix */
  1740.  
  1741.     noreal = !delit;
  1742.     for (p = lpre; *p && *p != String && *p != Tick; p++);
  1743.     tt = ic ? lpre + 1 : lpre;
  1744.     rpre = (*p || *lpre == Tilde || *lpre == Equals) ?
  1745.     (noreal = 0, getreal(tt)) :
  1746.     ztrdup(tt);
  1747.  
  1748.     for (p = lsuf; *p && *p != String && *p != Tick; p++);
  1749.     rsuf = *p ? (noreal = 0, getreal(lsuf)) : ztrdup(lsuf);
  1750.  
  1751.  /* check if word is a pattern */
  1752.  
  1753.     for (s1 = NULL, sf1 = 0, p = rpre + (rpl = strlen(rpre)) - 1;
  1754.      p >= rpre && (ispattern != 3 || !sf1);
  1755.      p--)
  1756.     if (itok(*p) && (p > rpre || (*p != Equals && *p != Tilde)))
  1757.         ispattern |= sf1 ? 1 : 2;
  1758.     else if (*p == '/') {
  1759.         sf1++;
  1760.         if (!s1)
  1761.         s1 = p;
  1762.     }
  1763.     for (s2 = NULL, sf2 = t = 0, p = rsuf; *p && (!t || !sf2); p++)
  1764.     if (itok(*p))
  1765.         t |= sf2 ? 4 : 2;
  1766.     else if (*p == '/') {
  1767.         sf2++;
  1768.         if (!s2)
  1769.         s2 = p;
  1770.     }
  1771.     ispattern = ispattern | t;
  1772.  
  1773.     if (!useglob)
  1774.     ispattern = 0;
  1775.  
  1776.     if (ispattern) {
  1777.     p = (char *) ncalloc(rpl + rsl + 2);
  1778.     strcpy(p, rpre);
  1779.     if (rpl && p[rpl - 1] != Star) {
  1780.         p[rpl] = Star;
  1781.         strcpy(p + rpl + 1, rsuf);
  1782.     }
  1783.     else
  1784.         strcpy(p + rpl, rsuf);
  1785.     patcomp = parsereg(p);
  1786.     }
  1787.     if (!patcomp) {
  1788.     untokenize(rpre);
  1789.     untokenize(rsuf);
  1790.  
  1791.     rpl = strlen(rpre);
  1792.     rsl = strlen(rsuf);
  1793.     }
  1794.     untokenize(lpre);
  1795.     untokenize(lsuf);
  1796.  
  1797.     lpl = strlen(lpre);
  1798.     lsl = strlen(lsuf);
  1799.  
  1800.  /* handle completion of files specially */
  1801.  
  1802.     if ((cc->mask & (CC_FILES | CC_COMMPATH)) || cc->glob) {
  1803.     if (!s1)
  1804.         s1 = rpre;
  1805.     if (!s2)
  1806.         s2 = rsuf + rsl;
  1807.  
  1808.     if (*s1 != '/')
  1809.         ppre = ztrdup("");
  1810.     else {
  1811.         if ((sav = *s1 ? s1[1] : '\0'))
  1812.         s1[1] = '\0';
  1813.         ppre = ztrdup(rpre);
  1814.         if (sav)
  1815.         s1[1] = sav;
  1816.     }
  1817.     psuf = ztrdup(s2);
  1818.  
  1819.     fpre = ztrdup(((s1 == s || s1 == rpre || ic) &&
  1820.                (*s != '/' || cs == wb)) ? s1 : s1 + 1);
  1821.     sav = *s2;
  1822.     *s2 = '\0';
  1823.     fsuf = ztrdup(rsuf);
  1824.     *s2 = sav;
  1825.  
  1826.     if (useglob && (ispattern & 2)) {
  1827.         int t2;
  1828.  
  1829.         p = (char *) ncalloc((t2 = strlen(fpre)) + strlen(fsuf) + 2);
  1830.         strcpy(p, fpre);
  1831.         if ((!t2 || p[t2 - 1] != Star) && *fsuf != Star)
  1832.         p[t2++] = Star;
  1833.         strcpy(p + t2, fsuf);
  1834.         filecomp = parsereg(p);
  1835.     }
  1836.     if (!filecomp) {
  1837.         untokenize(fpre);
  1838.         untokenize(fsuf);
  1839.  
  1840.         fpl = strlen(fpre);
  1841.         fsl = strlen(fsuf);
  1842.     }
  1843.     addwhat = -1;
  1844.  
  1845.     if (ic == Tilde)
  1846.         maketildelist();
  1847.     else if (ic == Equals) {
  1848.         if (isset(HASHLISTALL))
  1849.         fullhash();
  1850.         dumphtable(cmdnamtab, -7);
  1851.     } else {
  1852.         if (ispattern & 1) {
  1853.         Lklist l = newlist();
  1854.         Lknode n;
  1855.         int ng = opts[NULLGLOB];
  1856.  
  1857.         opts[NULLGLOB] = OPT_SET;
  1858.  
  1859.         addwhat = 0;
  1860.         p = (char *) ncalloc(lpl + lsl + 3);
  1861.         strcpy(p, lpre);
  1862.         if (*lsuf != '*' && *lpre && lpre[lpl-1] != '*')
  1863.             strcat(p, "*");
  1864.         strcat(p, lsuf);
  1865.         if (*lsuf && lsuf[lsl-1] != '*' && lsuf[lsl-1] != ')')
  1866.             strcat(p, "*");
  1867.  
  1868.         tokenize(p);
  1869.         addnode(l, p);
  1870.         postfork(l, 1);
  1871.  
  1872.         if (full(l)) {
  1873.             haswhat |= HAS_PATHPAT;
  1874.             for (n = firstnode(l); n; incnode(n))
  1875.             addmatch(getdata(n), NULL);
  1876.         }
  1877.         opts[NULLGLOB] = ng;
  1878.         } else {
  1879.         addwhat = CC_FILES;
  1880.         prpre = ztrdup(ppre);
  1881.  
  1882.         if (sf2)
  1883.             gen_matches_files(1, 0, 0);
  1884.         else {
  1885.             if (cc->mask & CC_FILES)
  1886.             gen_matches_files(0, 0, 1);
  1887.             else if (cc->mask & CC_COMMPATH) {
  1888.             if (sf1)
  1889.                 gen_matches_files(1, 1, 0);
  1890.             else {
  1891.                 char **pc = path, *pp = prpre;
  1892.  
  1893.                 for (; *pc; pc++)
  1894.                 if (pc[0][0] == '.' && !pc[0][1])
  1895.                     break;
  1896.                 if (*pc) {
  1897.                 prpre = "./";
  1898.                 gen_matches_files(1, 1, 0);
  1899.                 prpre = pp;
  1900.                 }
  1901.             }
  1902.             }
  1903.             if (cc->glob) {
  1904.             int ns, pl = strlen(prpre), o;
  1905.             char *g = dupstring(cc->glob), pa[MAXPATHLEN];
  1906.             char *p2, *p3;
  1907.             int ne = noerrs, md = opts[MARKDIRS];
  1908.             
  1909.             glob_pre = fpre;
  1910.             glob_suf = fsuf;
  1911.             
  1912.             noerrs = 1;
  1913.             addwhat = -6;
  1914.             strcpy(pa, prpre);
  1915.             o = strlen(pa);
  1916.             opts[MARKDIRS] = OPT_UNSET;
  1917.  
  1918.             while (*g) {
  1919.                 Lklist l = newlist();
  1920.  
  1921.                 while (*g && inblank(*g))
  1922.                 g++;
  1923.                 if (!*g)
  1924.                 break;
  1925.                 for (p = g + 1; *p && !inblank(*p); p++)
  1926.                 if (*p == '\\' && p[1])
  1927.                     p++;
  1928.                 sav = *p;
  1929.                 *p = '\0';
  1930.                 tokenize(g = dupstring(g));
  1931.                 if (*g == Equals || *g == Tilde) {
  1932.                 filesub(&g,0);
  1933.                 addnode(l, dupstring(g));
  1934.                 } else if (*g == '/')
  1935.                 addnode(l, dupstring(g));
  1936.                 else {
  1937.                 strcpy(pa + o, g);
  1938.                 addnode(l, dupstring(pa));
  1939.                 }
  1940.                 postfork(l, 1);
  1941.                 if (full(l) && peekfirst(l)) {
  1942.                 for (p2 = (char *)peekfirst(l); *p2; p2++)
  1943.                     if (itok(*p2))
  1944.                     break;
  1945.                 if (!*p2) {
  1946.                     if (*g == Equals || *g == Tilde || *g == '/') {
  1947.                     while ((p2 = (char *)ugetnode(l)))
  1948.                         if (strpfx(prpre, p2))
  1949.                         addmatch(p2 + pl, NULL);
  1950.                     } else {
  1951.                     while ((p2 = p3 = (char *)ugetnode(l))) {
  1952.                         for (ns = sf1; *p3 && ns; p3++)
  1953.                         if (*p3 == '/')
  1954.                             ns--;
  1955.  
  1956.                         addmatch(p3, NULL);
  1957.                     }
  1958.                     }
  1959.                 }
  1960.                 }
  1961.                 pa[o] = '\0';
  1962.                 *p = sav;
  1963.                 g = p;
  1964.             }
  1965.             glob_pre = glob_suf = NULL;
  1966.             noerrs = ne;
  1967.             opts[MARKDIRS] = md;
  1968.             }
  1969.         }
  1970.         }
  1971.     }
  1972.     }
  1973.  
  1974.     /* Use tricat() instead of dyncat() to get zalloc()'d memory */
  1975.     if (ic == Tilde || ic == Equals) {
  1976.     char *orpre = rpre;
  1977.     rpre = tricat("", (ic == Tilde) ? "~" : "=", rpre);
  1978.     rpl++;
  1979.     zsfree(orpre);
  1980.     }
  1981.  
  1982.     if (!ic && (cc->mask & CC_COMMPATH) && !*ppre && !*psuf) {
  1983.     dumphtable(aliastab, -2);
  1984.     if (isset(HASHLISTALL))
  1985.         fullhash();
  1986.     dumphtable(cmdnamtab, -3);
  1987.     if (isset(AUTOCD) && isset(CDABLEVARS))
  1988.         dumphtable(paramtab, -4);
  1989.     }
  1990.     addwhat = -2;
  1991.  
  1992.     if (cc->mask & CC_OPTIONS) {
  1993.     struct option *o;
  1994.  
  1995.     for (o = optns; o->name; o++)
  1996.         addmatch(dupstring(o->name), NULL);
  1997.     }
  1998.     if (cc->mask & CC_VARS)
  1999.     dumphtable(paramtab, -2);
  2000.     if (cc->mask & CC_BINDINGS) {
  2001.     int t0;
  2002.  
  2003.     for (t0 = 0; t0 != ZLECMDCOUNT; t0++)
  2004.         if (*zlecmds[t0].name)
  2005.         addmatch(dupstring(zlecmds[t0].name), NULL);
  2006.     }
  2007.     if (cc->keyvar) {
  2008.     char **usr = get_user_var(cc->keyvar);
  2009.  
  2010.     if (usr)
  2011.         while (*usr)
  2012.         addmatch(*usr++, NULL);
  2013.     }
  2014.     if (cc->mask & CC_USERS)
  2015.     maketildelist();
  2016.     if (cc->func) {
  2017.     List list;
  2018.     char **r;
  2019.     int lv = lastval;
  2020.  
  2021.     if ((list = getshfunc(cc->func))) {
  2022.         Lklist args = newlist();
  2023.  
  2024.         addnode(args, cc->func);
  2025.  
  2026.         if (delit) {
  2027.         sav = os[ooffs];
  2028.         os[ooffs] = '\0';
  2029.         p = dupstring(os);
  2030.         untokenize(p);
  2031.         addnode(args, p);
  2032.         os[ooffs] = sav;
  2033.         p = dupstring(os + ooffs);
  2034.         untokenize(p);
  2035.         addnode(args, p);
  2036.         }
  2037.         else {
  2038.         addnode(args, lpre);
  2039.         addnode(args, lsuf);
  2040.         }
  2041.  
  2042.         inzlefunc = 1;
  2043.         doshfuncnoval(list, args, 0);
  2044.         inzlefunc = 0;
  2045.         if ((r = get_user_var("reply")))
  2046.         while (*r)
  2047.             addmatch(*r++, NULL);
  2048.     }
  2049.     lastval = lv;
  2050.     }
  2051.     if (cc->mask & (CC_JOBS | CC_RUNNING | CC_STOPPED)) {
  2052.     int i;
  2053.     char *j, *jj;
  2054.  
  2055.     for (i = 0; i < MAXJOB; i++)
  2056.         if (jobtab[i].stat & STAT_INUSE) {
  2057.         int stopped = jobtab[i].stat & STAT_STOPPED;
  2058.  
  2059.         j = jj = dupstring(jobtab[i].procs->text);
  2060.         for (; *jj; jj++)
  2061.             if (*jj == ' ') {
  2062.             *jj = '\0';
  2063.             break;
  2064.             }
  2065.         if ((cc->mask & CC_JOBS) || (stopped && (cc->mask & CC_STOPPED))
  2066.             || (!stopped && (cc->mask & CC_RUNNING)))
  2067.             addmatch(j, NULL);
  2068.         }
  2069.     }
  2070.     if (cc->str) {
  2071.     Lklist foo = newlist();
  2072.     Lknode n;
  2073.     int first = 1, ng = opts[NULLGLOB], oowe = we, oowb = wb;
  2074.  
  2075.     opts[NULLGLOB] = OPT_SET;
  2076.  
  2077.     zleparse = 1;
  2078.     lexsave();
  2079.     hungets(cc->str);
  2080.     hungets("foo ");        /* KLUDGE! */
  2081.     strinbeg();
  2082.     noaliases = 1;
  2083.     do {
  2084.         ctxtlex();
  2085.         if (tok == ENDINPUT)
  2086.         break;
  2087.         if (!first && tokstr && *tokstr)
  2088.         addnode(foo, ztrdup(tokstr));
  2089.         first = 0;
  2090.     }
  2091.     while (tok != ENDINPUT && zleparse);
  2092.     noaliases = 0;
  2093.     hflush();
  2094.     strinend();
  2095.     errflag = zleparse = 0;
  2096.     lexrestore();
  2097.     prefork(foo, 0);
  2098.     if (!errflag) {
  2099.         postfork(foo, 1);
  2100.         if (!errflag)
  2101.         for (n = firstnode(foo); n; incnode(n))
  2102.             addmatch((char *)n->dat, NULL);
  2103.     }
  2104.     opts[NULLGLOB] = ng;
  2105.     we = oowe;
  2106.     wb = oowb;
  2107.     }
  2108.     if (cc->hpat) {
  2109.     Comp compc = NULL;
  2110.     char *e, *h, hpatsav;
  2111.     int i = curhist - 1, n = cc->hnum, l = lithist;
  2112.  
  2113.     if (*(cc->hpat)) {
  2114.         char *thpat = dupstring(cc->hpat);
  2115.  
  2116.         tokenize(thpat);
  2117.         compc = parsereg(thpat);
  2118.     }
  2119.     if (!n)
  2120.         n = -1;
  2121.     lithist = 0;
  2122.  
  2123.     while (n-- && (h = qgetevent(i--))) {
  2124.         while (*h) {
  2125.         for (e = h; *e && *e != HISTSPACE; e++);
  2126.         hpatsav = *e;
  2127.         *e = '\0';
  2128.         if (*h != '\'' && *h != '"' && *h != '`' && *h != '$' &&
  2129.             (!compc || domatch(h, compc, 0)))
  2130.             addmatch(dupstring(h), NULL);
  2131.         if (hpatsav) {
  2132.             *e = hpatsav;
  2133.             h = e + 1;
  2134.         } else
  2135.             h = e;
  2136.         }
  2137.     }
  2138.     lithist = l;
  2139.     }
  2140.     if ((t = cc->mask & (CC_ARRAYS | CC_INTVARS | CC_ENVVARS | CC_SCALARS |
  2141.             CC_READONLYS | CC_SPECIALS | CC_PARAMS)))
  2142.     dumphtable(paramtab, t);
  2143.     if ((t = cc->mask & (CC_FUNCS | CC_BUILTINS | CC_DISCMDS | CC_EXCMDS)))
  2144.     dumphtable(cmdnamtab, t);
  2145.     if ((t = cc->mask & (CC_ALREG | CC_ALGLOB)))
  2146.     dumphtable(aliastab, t);
  2147.  
  2148.     expl = cc->explain;
  2149.  
  2150.     remsuffix = (cc->mask & CC_REMOVE);
  2151.     ccsuffix = cc->suffix;
  2152.  
  2153.     mpre = ztrdup(lpre);
  2154.     msuf = ztrdup(lsuf);
  2155.     quotepresuf(&lpre);
  2156.     quotepresuf(&lsuf);
  2157.     quotepresuf(&fpre);
  2158.     quotepresuf(&fsuf);
  2159.     quotepresuf(&ppre);
  2160.     quotepresuf(&psuf);
  2161.     
  2162.     if (empty(matches) || errflag) {
  2163.     if (cc->xor && !isp) {
  2164.         errflag = 0;
  2165.         cc = cc->xor;
  2166.         wb = owb;
  2167.         we = owe;
  2168.         cs = ocs;
  2169.         s = dupstring(os);
  2170.         strcpy((char *) line, (char *) ol);
  2171.         goto xorrec;
  2172.     }
  2173.     feep();
  2174.     } else if (lst == COMP_LIST_COMPLETE)
  2175.     listtlist(matches);
  2176.     else {
  2177.     if (delit) {
  2178.         wb -= compadd;
  2179.         strcpy((char *)line + wb, (char *)line + we);
  2180.         we = cs = wb;
  2181.     }
  2182.  
  2183.     if (nextnode(firstnode(matches)))
  2184.         do_ambiguous();
  2185.     else
  2186.         do_single((char *)peekfirst(matches));
  2187.     }
  2188.  
  2189.     if (expl && (empty(matches) || nextnode(firstnode(matches)))) {
  2190.     int up;
  2191.  
  2192.     trashzle();
  2193.     
  2194.     clearflag = (isset(USEZLE) && termok &&
  2195.         (isset(ALWAYSLASTPROMPT) && mult == 1)) ||
  2196.         (unset(ALWAYSLASTPROMPT) && mult != 1);
  2197.  
  2198.     up = printfmt(expl, countnodes(matches), 1);
  2199.  
  2200.     if (clearflag)
  2201.         tcmultout(TCUP, TCMULTUP, up + nlnct);
  2202.     fflush(stdout);
  2203.     }
  2204.  
  2205.     ll = strlen((char *)line);
  2206.     if (cs > ll)
  2207.     cs = ll;
  2208.   compend:
  2209.     if (ccmain != &cc_dummy)
  2210.     freecompctl(ccmain);
  2211.     popheap();
  2212.     permalloc();
  2213. }
  2214.  
  2215. char **get_user_var(nam)    /**/
  2216. char *nam;
  2217. {
  2218.     if (!nam)
  2219.     return NULL;
  2220.     else if (*nam == '(') {
  2221.     char *ptr, *s, **uarr, **aptr;
  2222.     int count = 0, nonempty = 0, brk = 0;
  2223.     Lklist arrlist = newlist();
  2224.  
  2225.     ptr = dupstring(nam);
  2226.     s = ptr + 1;
  2227.     while (*++ptr) {
  2228.         if (*ptr == '\\' && ptr[1])
  2229.         chuck(ptr), nonempty++;
  2230.         else if (*ptr == ',' || inblank(*ptr) || *ptr == ')') {
  2231.         if (*ptr == ')')
  2232.             brk++;
  2233.         if (nonempty) {
  2234.             *ptr = '\0';
  2235.             count++;
  2236.             if (*s == '\n')
  2237.             s++;
  2238.             addnode(arrlist, s);
  2239.         }
  2240.         s = ptr + 1;
  2241.         nonempty = 0;
  2242.         } else
  2243.         nonempty++;
  2244.         if (brk)
  2245.         break;
  2246.     }
  2247.     if (!brk || !count)
  2248.         return NULL;
  2249.     *ptr = '\0';
  2250.     aptr = uarr = (char **)ncalloc(sizeof(char *) * (count + 1));
  2251.  
  2252.     while ((*aptr++ = (char *)ugetnode(arrlist)));
  2253.     uarr[count] = NULL;
  2254.     return uarr;
  2255.     } else
  2256.     return getaparam(nam);
  2257. }
  2258.  
  2259. int strbpcmp(a, b)    /**/
  2260. const void *a;
  2261. const void *b;
  2262. {
  2263.     char *aa = *((char **) a), *bb = *((char **) b);
  2264.  
  2265.     for (; *aa; aa++, bb++) {
  2266.     if (*aa == '\\')
  2267.         aa++;
  2268.     if (*bb == '\\')
  2269.         bb++;
  2270.     if (*aa != *bb)
  2271.         return (int) (*aa - *bb);
  2272.     }
  2273.     return 0;
  2274. }
  2275.  
  2276. void do_ambiguous()
  2277. {                /**/
  2278.     char **ap, **bp, **cp;
  2279.     int p, atend = (cs == we);
  2280.     Lknode nod;
  2281.  
  2282.     lastambig = 1;
  2283.  
  2284.     if (menuarr) {
  2285.     freearray(menuarr);
  2286.     menuarr = NULL;
  2287.     menucmp = 0;
  2288.     }
  2289.     ap = amatches = (char **)ncalloc(((nmatches = countnodes(matches)) + 1) *
  2290.                      sizeof(char *));
  2291.  
  2292.     for (nod = firstnode(matches); nod; incnode(nod))
  2293.     *ap++ = (char *) getdata(nod);
  2294.     *ap = NULL;
  2295.  
  2296.     qsort((vptr) amatches, nmatches, sizeof(char *),
  2297.            (int (*)DCLPROTO((const void *, const void *)))strbpcmp);
  2298.  
  2299.     for (ap = cp = amatches; *ap; ap++) {
  2300.     *cp++ = *ap;
  2301.     for (bp = ap; bp[1] && !strcmp(*ap, bp[1]); bp++);
  2302.     ap = bp;
  2303.     }
  2304.     *cp = NULL;
  2305.  
  2306.     if ((nmatches = arrlen(amatches)) == 1) {
  2307.     do_single(amatches[0]);
  2308.     return;
  2309.     }
  2310.  
  2311.     complexpect = 0;
  2312.  
  2313.     if ((p = (usemenu || ispattern)) || isset(AUTOMENU)) {
  2314.     permalloc();
  2315.     menuarr = arrdup(amatches);
  2316.     heapalloc();
  2317.     }
  2318.     if (shortest && shortl == 0 && isset(RECEXACT) &&
  2319.     (usemenu == 0 || unset(AUTOMENU))) {
  2320.     do_single(shortest);
  2321.     } else {
  2322.     if (p)
  2323.         do_ambig_menu();
  2324.     else {
  2325.         if (ab)
  2326.         inststrlen(firstm, 1, ab);
  2327.         if (ae && !atend)
  2328.         inststrlen(firstm + strlen(firstm) - ae, 0, ae);
  2329.         if (isset(LISTAMBIGUOUS) && (ab || (ae && !atend))) { 
  2330.         lastambig = 0;
  2331.         return;
  2332.         }
  2333.     }
  2334.     if (unset(NOLISTBEEP))
  2335.         feep();
  2336.     if (isset(AUTOLIST) && !amenu)
  2337.         listmatches();
  2338.     }
  2339. }
  2340.  
  2341. int ztat(nam, buf, ls)        /**/
  2342. char *nam;
  2343. struct stat *buf;
  2344. int ls;
  2345. {
  2346.     char b[MAXPATHLEN], *p;
  2347.  
  2348.     for (p = b; *nam; nam++)
  2349.     if (*nam == '\\' && nam[1])
  2350.         *p++ = *++nam;
  2351.     else
  2352.         *p++ = *nam;
  2353.     *p = '\0';
  2354.  
  2355.     return ls ? lstat(b, buf) : stat(b, buf);
  2356. }
  2357.  
  2358. void do_single(str)        /**/
  2359. char *str;
  2360. {
  2361.     int ccs, l, insc = 0;
  2362.     char singlec = ' ';
  2363.  
  2364.     addedsuffix = 0;
  2365.  
  2366.     if (!menucur) {
  2367.     if (ispattern) {
  2368.         cs = we;
  2369.         menupos = wb;
  2370.     } else
  2371.         menupos = cs;
  2372.     menuwe = (cs == we);
  2373.     if (ccsuffix && !(haswhat & HAS_SUFFIX)) {
  2374.         if (*ccsuffix) {
  2375.         ccs = cs;
  2376.         cs = we;
  2377.         inststrlen(ccsuffix, menuwe, -1);
  2378.         menuend = cs;
  2379.         cs = ccs;
  2380.         if (remsuffix)
  2381.             addedsuffix = strlen(ccsuffix);
  2382.         } else
  2383.         menuend = we;
  2384.  
  2385.         haswhat |= HAS_SUFFIX;
  2386.     } else
  2387.         menuend = we;
  2388.     }
  2389.     ccs = cs;
  2390.     cs = menupos;
  2391.     if (menucur)
  2392.     l = menulen;
  2393.     else if (ispattern)
  2394.     l = we - wb;
  2395.     else
  2396.     l = 0;
  2397.  
  2398.     if (l) {
  2399.     foredel(l);
  2400.     if (menuwe)
  2401.         ccs -= l;
  2402.     menuend -= l;
  2403.     }
  2404.     inststrlen(str, 1, menulen = strlen(str));
  2405.  
  2406.     if (menuwe)
  2407.     cs = ccs + menulen;
  2408.     menuend += menulen;
  2409.  
  2410.     if (!(haswhat & HAS_SUFFIX)) {
  2411.     if (!(haswhat & HAS_MISC)) {
  2412.         char p[MAXPATHLEN], *ss;
  2413.         struct stat buf;
  2414.  
  2415.         if (ispattern || ic) {
  2416.         int ne = noerrs;
  2417.  
  2418.         noerrs = 1;
  2419.  
  2420.         if (ic) {
  2421.             *p = ic;
  2422.             sprintf(p + 1, "%s%s%s%s", fpre, str, fsuf, psuf);
  2423.         } else
  2424.             strcpy(p, str);
  2425.         ss = dupstring(p);
  2426.         singsub(&ss);
  2427.         strcpy(p, ss);
  2428.  
  2429.         noerrs = ne;
  2430.         } else
  2431.         sprintf(p, "%s%s%s%s%s",
  2432.             (prpre && *prpre) ? prpre : "./", fpre, str,
  2433.             fsuf, psuf);
  2434.         if (!ztat(p, &buf, 0) && (buf.st_mode & S_IFMT) == S_IFDIR) {
  2435.         singlec = '/';
  2436.         if (menuwe)
  2437.             addedsuffix = isset(AUTOREMOVESLASH) ? 1 : 0;
  2438.         }
  2439.     }
  2440.     if (menuend > ll)
  2441.         menuend = ll;
  2442.     if (menuend &&     ((char) line[menuend - 1]) != singlec)
  2443.         if (!menucur || !line[menuend]) {
  2444.         ccs = cs;
  2445.         cs = menuend;
  2446.         inststrlen((char *)&singlec, 1, 1);
  2447.         insc = 1;
  2448.         if (!menuwe)
  2449.             cs = ccs;
  2450.         } else
  2451.         line[menuend] = (unsigned char)singlec;
  2452.     }
  2453.     if (isset(ALWAYSTOEND) || menuwe)
  2454.     cs = menuend + !(haswhat & HAS_SUFFIX);
  2455.     if (menucmp && singlec == ' ' && !(haswhat & HAS_SUFFIX)) {
  2456.     if (insc)
  2457.         backdel(1);
  2458.     else
  2459.         cs--;
  2460.     }
  2461. }
  2462.  
  2463. void do_ambig_menu()
  2464. {                /**/
  2465.     menucmp = 1;
  2466.     menucur = NULL;
  2467.     do_single(*menuarr);
  2468.     menucur = menuarr;
  2469. }
  2470.  
  2471. int strpfx(s, t)        /**/
  2472. char *s;
  2473. char *t;
  2474. {
  2475.     while (*s && *s == *t)
  2476.     s++, t++;
  2477.     return !*s;
  2478. }
  2479.  
  2480. int strsfx(s, t)        /**/
  2481. char *s;
  2482. char *t;
  2483. {
  2484.     int ls = strlen(s), lt = strlen(t);
  2485.  
  2486.     if (ls <= lt)
  2487.     return !strcmp(t + lt - ls, s);
  2488.     return 0;
  2489. }
  2490.  
  2491. int pfxlen(s, t)        /**/
  2492. char *s;
  2493. char *t;
  2494. {
  2495.     int i = 0;
  2496.  
  2497.     while (*s && *s == *t)
  2498.     s++, t++, i++;
  2499.     return i;
  2500. }
  2501.  
  2502. int sfxlen(s, t)        /**/
  2503. char *s;
  2504. char *t;
  2505. {
  2506.     if (*s && *t) {
  2507.     int i = 0;
  2508.     char *s2 = s + strlen(s) - 1, *t2 = t + strlen(t) - 1;
  2509.  
  2510.     while (s2 >= s && *s2 == *t2)
  2511.         s2--, t2--, i++;
  2512.  
  2513.     return i;
  2514.     } else
  2515.     return 0;
  2516. }
  2517.  
  2518. int printfmt(fmt, n, dopr)        /**/
  2519. char *fmt;
  2520. int n;
  2521. int dopr;
  2522. {
  2523.     char *p = fmt, nc[14];
  2524.     int l = 1, cc = 0;
  2525.  
  2526.     for (;*p;p++) {
  2527.     if (*p == '%')
  2528.         if (*++p) 
  2529.         switch(*p) {
  2530.           case '%':
  2531.             if (dopr)
  2532.             putchar('%');
  2533.             cc++;
  2534.             break;
  2535.           case 'n':
  2536.             sprintf(nc, "%d", n);
  2537.             if (dopr)
  2538.             printf(nc);
  2539.             cc += strlen(nc);
  2540.         }
  2541.         else
  2542.         break;
  2543.     else {
  2544.         cc++;
  2545.         if (*p == '\n') {
  2546.         l += 1 + (cc/columns);
  2547.         cc = 0;
  2548.         }
  2549.         if (dopr)
  2550.         putchar(*p);
  2551.     }
  2552.     }
  2553.     if (dopr)
  2554.     putchar('\n');
  2555.  
  2556.     return l + (cc/columns);
  2557. }
  2558.  
  2559. void listmatches()
  2560. {                /**/
  2561.     int longest = 1, fct, fw = 0, colsz, t0, t1, ct, up, cl;
  2562.     int off, boff;
  2563.     int of = (isset(LISTTYPES) && !(haswhat & HAS_MISC));
  2564.     char **arr, **ap, sav;
  2565.  
  2566.     off = ispattern && ppre && *ppre &&
  2567.     !(haswhat & (HAS_MISC|HAS_PATHPAT)) ? strlen(ppre) : 0;
  2568.     boff = ispattern && psuf && *psuf &&
  2569.     !(haswhat & (HAS_MISC|HAS_PATHPAT)) ? strlen(psuf) : 0;
  2570.  
  2571.     trashzle();
  2572.     ct = nmatches;
  2573.  
  2574.     clearflag = (isset(USEZLE) && termok &&
  2575.     (isset(ALWAYSLASTPROMPT) && mult == 1)) ||
  2576.     (unset(ALWAYSLASTPROMPT) && mult != 1);
  2577.  
  2578.     arr = amatches;
  2579.  
  2580.     for (ap = arr; *ap; ap++)
  2581.     if ((cl = strlen(*ap + off) - boff +
  2582.          (ispattern ? 0 :
  2583.           (!(haswhat & HAS_MISC) ? fpl + fsl : lpl + lsl))) > longest)
  2584.         longest = cl;
  2585.     if (of)
  2586.     longest++;
  2587.  
  2588.     fct = (columns - 1) / (longest + 2);
  2589.     if (fct == 0)
  2590.     fct = 1;
  2591.     else
  2592.     fw = (columns - 1) / fct;
  2593.     colsz = (ct + fct - 1) / fct;
  2594.  
  2595.     up = colsz + nlnct - clearflag;
  2596.  
  2597.     if (expl)
  2598.     up += printfmt(expl, ct, 0);
  2599.  
  2600.     if ((listmax && ct > listmax) || (!listmax && up >= lines)) {
  2601.     fprintf(stdout, "zsh: do you wish to see all %d possibilities? ", ct);
  2602.     fflush(stdout);
  2603.     if (getquery() != 'y') {
  2604.         if (clearflag) {
  2605.         tcmultout(TCUP, TCMULTUP, 1);
  2606.         if (tccan(TCCLEAREOD))
  2607.             tcout(TCCLEAREOD);
  2608.         tcmultout(TCUP, TCMULTUP, nlnct);
  2609.         }
  2610.         return;
  2611.     }
  2612.     if (clearflag) {
  2613.         tcout(TCUP);
  2614.         if (tccan(TCCLEAREOD))
  2615.         tcout(TCCLEAREOD);
  2616.     }
  2617.     }
  2618.     if (expl)
  2619.     printfmt(expl, ct, 1);
  2620.  
  2621.     for (t1 = 0; t1 != colsz; t1++) {
  2622.     ap = arr + t1;
  2623.     if (of) {
  2624.         while (*ap) {
  2625.         int t2 = ispattern ? strlen(*ap) :
  2626.             strlen(*ap + off) - boff + 1 + fpl + fsl;
  2627.         char pbuf[MAXPATHLEN], *pb;
  2628.         struct stat buf;
  2629.  
  2630.         if (ispattern) {
  2631.             sav = ap[0][t2 - boff];
  2632.             ap[0][t2 - boff] = '\0';
  2633.             printf("%s", *ap + off);
  2634.             ap[0][t2 - boff] = sav;    
  2635.             pb = *ap;
  2636.             t2 -= off + boff - 1;
  2637.         } else {
  2638.             printf("%s%s%s", fpre, *ap, fsuf);
  2639.             sprintf(pb = pbuf, "%s%s%s%s",
  2640.                 (prpre && *prpre) ? prpre : "./", fpre, *ap, fsuf);
  2641.         }
  2642.         if (ztat(pb, &buf, 1))
  2643.             putchar(' ');
  2644.         else
  2645.             putchar(file_type(buf.st_mode));
  2646.         for (t0 = colsz; t0 && *ap; t0--, ap++);
  2647.         if (*ap)
  2648.             for (; t2 < fw; t2++)
  2649.             putchar(' ');
  2650.         }
  2651.     } else
  2652.         while (*ap) {
  2653.         int t2 = ispattern ? strlen(*ap) :
  2654.             strlen(*ap + off) - boff;
  2655.  
  2656.         if (ispattern) {
  2657.             sav = ap[0][t2 - boff];
  2658.             ap[0][t2 - boff] = '\0';
  2659.             printf("%s", *ap + off);
  2660.             ap[0][t2 - boff] = sav;
  2661.             t2 -= off + boff;
  2662.         } else if (!(haswhat & HAS_MISC)) {
  2663.             printf("%s%s%s", fpre, *ap, fsuf);
  2664.             t2 += fpl + fsl;
  2665.         }
  2666.         else {
  2667.             printf("%s%s%s", lpre, *ap, lsuf);
  2668.             t2 += lpl + lsl;
  2669.         }
  2670.         for (t0 = colsz; t0 && *ap; t0--, ap++);
  2671.         if (*ap)
  2672.             for (; t2 < fw; t2++)
  2673.             putchar(' ');
  2674.         }
  2675.     if (t1 != colsz - 1 || !clearflag)
  2676.         putchar('\n');
  2677.     }
  2678.     if (clearflag)
  2679.     if (up < lines)
  2680.         tcmultout(TCUP, TCMULTUP, up);
  2681.     else
  2682.         clearflag = 0, putchar('\n');
  2683.  
  2684.     expl = NULL;
  2685.  
  2686.     fflush(stdout);
  2687. }
  2688.  
  2689. void listtlist(l)        /**/
  2690. Lklist l;
  2691. {
  2692.     int n = countnodes(l), nm = nmatches;
  2693.     char **am = amatches, **ap, **bp, **cp;
  2694.     Lknode nod;
  2695.  
  2696.     nmatches = n;
  2697.  
  2698.     amatches = ap = (char **)ncalloc((n + 1) * sizeof(char *));
  2699.  
  2700.     for (nod = firstnode(l); nod; incnode(nod))
  2701.     *ap++ = (char *)getdata(nod);
  2702.     *ap = NULL;
  2703.  
  2704.     qsort((vptr) amatches, nmatches, sizeof(char *),
  2705.            (int (*)DCLPROTO((const void *, const void *)))strpcmp);
  2706.  
  2707.     for (ap = cp = amatches; *ap; ap++) {
  2708.     *cp++ = *ap;
  2709.     for (bp = ap; bp[1] && !strcmp(*ap, bp[1]); bp++);
  2710.     ap = bp;
  2711.     }
  2712.     *cp = NULL;
  2713.  
  2714.     listmatches();
  2715.  
  2716.     amatches = am;
  2717.     nmatches = nm;
  2718. }
  2719.  
  2720. void listlist(l)        /**/
  2721. Lklist l;
  2722. {
  2723.     int hw = haswhat, ip = ispattern;
  2724.     char *lp = lpre, *ls = lsuf;
  2725.  
  2726.     haswhat = HAS_MISC;
  2727.     ispattern = 0;
  2728.     lpre = lsuf = "";
  2729.  
  2730.     listtlist(l);
  2731.  
  2732.     lpre = lp;
  2733.     lsuf = ls;
  2734.     ispattern = ip;
  2735.     haswhat = hw;
  2736. }
  2737.  
  2738. void selectlist(l)        /**/
  2739. Lklist l;
  2740. {
  2741.     int longest = 1, fct, fw = 0, colsz, t0, t1, ct;
  2742.     Lknode n;
  2743.     char **arr, **ap;
  2744.  
  2745.     trashzle();
  2746.     ct = countnodes(l);
  2747.     ap = arr = (char **)alloc((countnodes(l) + 1) * sizeof(char **));
  2748.  
  2749.     for (n = (Lknode) firstnode(l); n; incnode(n))
  2750.     *ap++ = (char *)getdata(n);
  2751.     *ap = NULL;
  2752.     for (ap = arr; *ap; ap++)
  2753.     if (strlen(*ap) > longest)
  2754.         longest = strlen(*ap);
  2755.     t0 = ct;
  2756.     longest++;
  2757.     while (t0)
  2758.     t0 /= 10, longest++;
  2759.     fct = (columns - 1) / (longest + 3);    /* to compensate for added ')' */
  2760.     if (fct == 0)
  2761.     fct = 1;
  2762.     else
  2763.     fw = (columns - 1) / fct;
  2764.     colsz = (ct + fct - 1) / fct;
  2765.     for (t1 = 0; t1 != colsz; t1++) {
  2766.     ap = arr + t1;
  2767.     do {
  2768.         int t2 = strlen(*ap) + 2, t3;
  2769.  
  2770.         fprintf(stderr, "%d) %s", t3 = ap - arr + 1, *ap);
  2771.         while (t3)
  2772.         t2++, t3 /= 10;
  2773.         for (; t2 < fw; t2++)
  2774.         fputc(' ', stderr);
  2775.         for (t0 = colsz; t0 && *ap; t0--, ap++);
  2776.     }
  2777.     while (*ap);
  2778.     fputc('\n', stderr);
  2779.     }
  2780.  
  2781.  /* Below is a simple attempt at doing it the Korn Way..
  2782.        ap = arr;
  2783.        t0 = 0;
  2784.        do
  2785.        {
  2786.        t0++;
  2787.        fprintf(stderr,"%d) %s\n",t0,*ap);
  2788.        ap++;
  2789.        }
  2790.        while (*ap);*/
  2791.     fflush(stderr);
  2792. }
  2793.  
  2794. int doexpandhist()
  2795. {                /**/
  2796.     unsigned char *cc, *ce, oc = ' ', ooc = ' ';
  2797.     int t0, oldcs, oldll;
  2798.  
  2799.     for (cc = line, ce = line + ll; cc < ce; ooc = oc, oc = *cc++)
  2800.     if (*cc == '\\' && cc[1])
  2801.         cc++;
  2802.     else if ((*cc == bangchar && oc != '>' && (oc != '&' || ooc != '>')) ||
  2803.          (*cc == hatchar && *line == hatchar && cc != line))
  2804.         break;
  2805.     if (*cc == bangchar && cc[1] == '"')
  2806.     return 3;
  2807.     if (cc == ce)
  2808.     return 2;
  2809.     oldcs = cs;
  2810.     oldll = ll;
  2811.     zleparse = 1;
  2812.     lexsave();
  2813.     hungets(UTOSCP(line));
  2814.     strinbeg();
  2815.     pushheap();
  2816.     ll = cs = 0;
  2817.     for (;;) {
  2818.     t0 = hgetc();
  2819.     if (lexstop)
  2820.         break;
  2821.     spaceinline(1);
  2822.     line[cs++] = t0;
  2823.     }
  2824.     hflush();
  2825.     popheap();
  2826.     strinend();
  2827.     errflag = zleparse = 0;
  2828.     t0 = histdone;
  2829.     lexrestore();
  2830.     line[ll = cs] = '\0';
  2831.     if (ll == oldll)
  2832.     cs = oldcs;
  2833.     return t0;
  2834. }
  2835.  
  2836. void magicspace()
  2837. {                /**/
  2838.     c = ' ';
  2839.     selfinsert();
  2840.     doexpandhist();
  2841. }
  2842.  
  2843. void expandhistory()
  2844. {                /**/
  2845.     if (!doexpandhist())
  2846.     feep();
  2847. }
  2848.  
  2849. static int cmdwb, cmdwe;
  2850.  
  2851. char *getcurcmd()
  2852. {                /**/
  2853.     int curlincmd;
  2854.     char *s = NULL;
  2855.  
  2856.     zleparse = 1;
  2857.     lexsave();
  2858.     hungets(" ");        /* KLUDGE! */
  2859.     hungets(UTOSCP(line));
  2860.     strinbeg();
  2861.     pushheap();
  2862.     do {
  2863.     curlincmd = incmdpos;
  2864.     ctxtlex();
  2865.     if (tok == ENDINPUT)
  2866.         break;
  2867.     if (tok == STRING && curlincmd) {
  2868.         zsfree(s);
  2869.         s = ztrdup(tokstr);
  2870.         cmdwb = ll - wordbeg;
  2871.         cmdwe = ll + 1 - inbufct;
  2872.     }
  2873.     }
  2874.     while (tok != ENDINPUT && zleparse);
  2875.     hflush();
  2876.     popheap();
  2877.     strinend();
  2878.     errflag = zleparse = 0;
  2879.     lexrestore();
  2880.     return s;
  2881. }
  2882.  
  2883. void processcmd()
  2884. {                /**/
  2885.     char *s, *t;
  2886.  
  2887.     s = getcurcmd();
  2888.     if (!s) {
  2889.     feep();
  2890.     return;
  2891.     }
  2892.     t = zlecmds[bindk].name;
  2893.     mult = 1;
  2894.     permalloc();
  2895.     pushline();
  2896.     lastalloc();
  2897.     sizeline(strlen(s) + strlen(t) + 1);
  2898.     strcpy((char *)line, t);
  2899.     strcat((char *)line, " ");
  2900.     cs = ll = strlen((char *)line);
  2901.     inststr(s);
  2902.     zsfree(s);
  2903.     done = 1;
  2904. }
  2905.  
  2906. void expandcmdpath()
  2907. {                /**/
  2908.     int oldcs = cs, na = noaliases;
  2909.     char *s, *str;
  2910.  
  2911.     noaliases = 1;
  2912.     s = getcurcmd();
  2913.     noaliases = na;
  2914.     if (!s || cmdwb < 0 || cmdwe < cmdwb) {
  2915.     feep();
  2916.     return;
  2917.     }
  2918.     str = findcmd(s);
  2919.     zsfree(s);
  2920.     if (!str) {
  2921.     feep();
  2922.     return;
  2923.     }
  2924.     cs = cmdwb;
  2925.     foredel(cmdwe - cmdwb);
  2926.     spaceinline(strlen(str));
  2927.     strncpy((char *)line + cs, str, strlen(str));
  2928.     cs = oldcs;
  2929.     if (cs >= cmdwe - 1)
  2930.     cs += cmdwe - cmdwb + strlen(str);
  2931.     if (cs > ll)
  2932.     cs = ll;
  2933.     zsfree(str);
  2934. }
  2935.  
  2936. /* Extra function added by AR Iano-Fletcher. */
  2937. /* This is a expand/complete in the vein of wash. */
  2938.  
  2939. void expandorcompleteprefix()
  2940. {                /**/
  2941.  /* global c is the current character typed. */
  2942.     int csafe = c;
  2943.  
  2944.  /* insert a space and backspace. */
  2945.     c = ' ';
  2946.     selfinsert();        /* insert the extra character */
  2947.     forwardchar();        /* move towards beginning */
  2948.  
  2949.  /* do the expansion/completion. */
  2950.     c = csafe;
  2951.     expandorcomplete();        /* complete. */
  2952.  
  2953.  /* remove the inserted space. */
  2954.     backwardchar();        /* move towards ends */
  2955.     deletechar();        /* delete the added space. */
  2956. }
  2957.